{"version":3,"sources":["/Users/shyun/comcom/ain-enterprise/ain-adk/dist/cjs/chunk-XL6CXITR.cjs","../../src/services/workflow-variable-resolver.service.ts"],"names":[],"mappings":"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","file":"/Users/shyun/comcom/ain-enterprise/ain-adk/dist/cjs/chunk-XL6CXITR.cjs","sourcesContent":[null,"import { StatusCodes } from \"http-status-codes\";\nimport { AinHttpError } from \"@/types/agent.js\";\nimport type {\n\tUserWorkflow,\n\tWorkflowDefinition,\n\tWorkflowTableColumnFormat,\n\tWorkflowVariable,\n\tWorkflowVariablePartSpec,\n} from \"@/types/memory.js\";\nimport {\n\tresolveTemplateRecord,\n\tresolveTemplateString,\n} from \"@/utils/template-variables.js\";\n\ntype WorkflowTextFields = Pick<\n\tUserWorkflow,\n\t| \"title\"\n\t| \"content\"\n\t| \"timezone\"\n\t| \"variables\"\n\t| \"variableValues\"\n\t| \"definition\"\n>;\n\ntype VariableReplacement = {\n\ttoken: string;\n\tvalue: string;\n\tresolveAt: \"creation\" | \"execution\";\n};\n\ntype ParsedDateValue = {\n\tyear: string;\n\tmonth?: string;\n\tday?: string;\n};\n\nfunction getVariableTokens(key: string, variable?: WorkflowVariable): string[] {\n\tconst tokens = [key];\n\tif (variable?.id && variable.id !== key) {\n\t\ttokens.push(variable.id);\n\t}\n\treturn [...new Set(tokens)];\n}\n\nfunction normalizePartSpecs(\n\tparts?: WorkflowVariable[\"parts\"],\n): Array<{ token: string; format: string; source: \"value\" | \"start\" | \"end\" }> {\n\tif (!parts) {\n\t\treturn [];\n\t}\n\n\tif (Array.isArray(parts)) {\n\t\treturn parts\n\t\t\t.map((part) => {\n\t\t\t\tconst token =\n\t\t\t\t\tpart.token ||\n\t\t\t\t\tpart.placeholder ||\n\t\t\t\t\tpart.id ||\n\t\t\t\t\tpart.key ||\n\t\t\t\t\tpart.name ||\n\t\t\t\t\tpart.label;\n\t\t\t\tif (!token) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttoken,\n\t\t\t\t\tformat:\n\t\t\t\t\t\tpart.format ||\n\t\t\t\t\t\tinferDatePartFormat(\n\t\t\t\t\t\t\tpart.key || part.name || part.label || part.id || token,\n\t\t\t\t\t\t),\n\t\t\t\t\tsource: part.source || \"value\",\n\t\t\t\t};\n\t\t\t})\n\t\t\t.filter(\n\t\t\t\t(\n\t\t\t\t\tpart,\n\t\t\t\t): part is {\n\t\t\t\t\ttoken: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t\tsource: \"value\" | \"start\" | \"end\";\n\t\t\t\t} => Boolean(part),\n\t\t\t);\n\t}\n\n\treturn Object.entries(parts)\n\t\t.map(([partKey, tokenOrSpec]) => {\n\t\t\tif (typeof tokenOrSpec === \"string\") {\n\t\t\t\tif (!tokenOrSpec.trim()) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttoken: tokenOrSpec,\n\t\t\t\t\tformat: inferDatePartFormat(partKey),\n\t\t\t\t\tsource: inferDatePartSource(partKey),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst spec = tokenOrSpec as WorkflowVariablePartSpec;\n\t\t\tconst token =\n\t\t\t\tspec.token ||\n\t\t\t\tspec.placeholder ||\n\t\t\t\tspec.id ||\n\t\t\t\tspec.key ||\n\t\t\t\tspec.name ||\n\t\t\t\tspec.label;\n\t\t\tif (!token) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttoken,\n\t\t\t\tformat: spec.format || inferDatePartFormat(partKey),\n\t\t\t\tsource: spec.source || inferDatePartSource(partKey),\n\t\t\t};\n\t\t})\n\t\t.filter(\n\t\t\t(\n\t\t\t\tpart,\n\t\t\t): part is {\n\t\t\t\ttoken: string;\n\t\t\t\tformat: string;\n\t\t\t\tsource: \"value\" | \"start\" | \"end\";\n\t\t\t} => Boolean(part?.token),\n\t\t);\n}\n\nfunction inferDatePartFormat(input: string): string {\n\tif (/year|년도|연도|yyyy/i.test(input)) {\n\t\treturn \"YYYY\";\n\t}\n\tif (/month|월|mm/i.test(input)) {\n\t\treturn \"MM\";\n\t}\n\tif (/day|일|dd/i.test(input)) {\n\t\treturn \"DD\";\n\t}\n\treturn \"YYYY-MM-DD\";\n}\n\nfunction inferDatePartSource(input: string): \"value\" | \"start\" | \"end\" {\n\tif (/^start/i.test(input)) {\n\t\treturn \"start\";\n\t}\n\tif (/^end/i.test(input)) {\n\t\treturn \"end\";\n\t}\n\treturn \"value\";\n}\n\nfunction parseDateValue(\n\tvalue: string,\n\tsource: \"value\" | \"start\" | \"end\",\n): ParsedDateValue | undefined {\n\tconst segments = value.split(/\\s*~\\s*/);\n\tconst target =\n\t\tsource === \"start\"\n\t\t\t? segments[0]\n\t\t\t: source === \"end\"\n\t\t\t\t? segments[segments.length - 1]\n\t\t\t\t: value;\n\tconst match = target.trim().match(/(\\d{4})[-/.]?(\\d{2})?[-/.]?(\\d{2})?/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tyear: match[1],\n\t\tmonth: match[2],\n\t\tday: match[3],\n\t};\n}\n\nfunction formatParsedDateValue(\n\tdateValue: ParsedDateValue,\n\tformat: string,\n): string {\n\treturn format\n\t\t.replace(\"YYYY\", dateValue.year)\n\t\t.replace(\"YY\", dateValue.year.slice(-2))\n\t\t.replace(\"MM\", dateValue.month || \"\")\n\t\t.replace(\"M\", dateValue.month ? String(Number(dateValue.month)) : \"\")\n\t\t.replace(\"DD\", dateValue.day || \"\")\n\t\t.replace(\"D\", dateValue.day ? String(Number(dateValue.day)) : \"\");\n}\n\nfunction buildVariableReplacements(\n\tvariableValues: Record<string, string>,\n\tvariables?: WorkflowTextFields[\"variables\"],\n): VariableReplacement[] {\n\tconst replacements: VariableReplacement[] = [];\n\n\tfor (const [key, variableValue] of Object.entries(variableValues)) {\n\t\tconst variable = variables?.[key];\n\t\tconst resolveAt = variable?.resolveAt ?? \"creation\";\n\n\t\tfor (const token of getVariableTokens(key, variable)) {\n\t\t\treplacements.push({ token, value: variableValue, resolveAt });\n\t\t}\n\n\t\tif (variable?.type !== \"date_parts\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const part of normalizePartSpecs(variable.parts)) {\n\t\t\tconst parsedDateValue = parseDateValue(variableValue, part.source);\n\t\t\tif (!parsedDateValue) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treplacements.push({\n\t\t\t\ttoken: part.token,\n\t\t\t\tvalue: formatParsedDateValue(parsedDateValue, part.format),\n\t\t\t\tresolveAt,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn replacements;\n}\n\nfunction applyReplacements(\n\tinput: string,\n\treplacements: VariableReplacement[],\n\tresolveAt: \"creation\" | \"execution\",\n): string {\n\tconst scopedReplacements = replacements.filter(\n\t\t(replacement) => replacement.resolveAt === resolveAt,\n\t);\n\n\treturn scopedReplacements.reduce((result, replacement) => {\n\t\tconst withOffsets = replaceOffsetExpressions(result, replacement);\n\t\treturn withOffsets.replaceAll(\n\t\t\t`{{${replacement.token}}}`,\n\t\t\treplacement.value,\n\t\t);\n\t}, input);\n}\n\nfunction replaceOffsetExpressions(\n\tinput: string,\n\treplacement: VariableReplacement,\n): string {\n\tconst pattern = new RegExp(\n\t\t`\\\\{\\\\{(${escapeRegExp(replacement.token)})([+-]\\\\d+)\\\\}\\\\}`,\n\t\t\"g\",\n\t);\n\n\treturn input.replace(pattern, (match, _token, rawOffset: string) => {\n\t\tconst offset = Number.parseInt(rawOffset, 10);\n\t\tconst resolved = applyOffset(replacement.value, offset);\n\t\treturn resolved ?? match;\n\t});\n}\n\nfunction applyOffset(value: string, offset: number): string | undefined {\n\tconst trimmed = value.trim();\n\n\t// YYYY-MM-DD (the shape date_parts values are stored in): offset is in days,\n\t// Date.UTC normalizes month/year rollover.\n\tconst dateMatch = trimmed.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n\tif (dateMatch) {\n\t\tconst [, year, month, day] = dateMatch;\n\t\treturn new Date(\n\t\t\tDate.UTC(Number(year), Number(month) - 1, Number(day) + offset),\n\t\t)\n\t\t\t.toISOString()\n\t\t\t.slice(0, 10);\n\t}\n\n\tif (!/^-?\\d+$/.test(trimmed)) {\n\t\treturn undefined;\n\t}\n\n\tconst nextValue = Number.parseInt(trimmed, 10) + offset;\n\tif (!Number.isFinite(nextValue)) {\n\t\treturn undefined;\n\t}\n\n\tconst isNegative = nextValue < 0;\n\tconst digits = trimmed.startsWith(\"-\") ? trimmed.slice(1) : trimmed;\n\tconst preserveWidth = /^0\\d+$/.test(digits);\n\tif (!preserveWidth) {\n\t\treturn nextValue.toString();\n\t}\n\n\treturn `${isNegative ? \"-\" : \"\"}${Math.abs(nextValue)\n\t\t.toString()\n\t\t.padStart(digits.length, \"0\")}`;\n}\n\nfunction escapeRegExp(input: string): string {\n\treturn input.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction replaceWorkflowVariablesInValue(\n\tvalue: unknown,\n\treplacements: VariableReplacement[],\n\tresolveAt: \"creation\" | \"execution\",\n): unknown {\n\tif (typeof value === \"string\") {\n\t\treturn applyReplacements(value, replacements, resolveAt);\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) =>\n\t\t\treplaceWorkflowVariablesInValue(item, replacements, resolveAt),\n\t\t);\n\t}\n\n\tif (value && typeof value === \"object\") {\n\t\t// Keys too: columnFormats / rowFormats are keyed by column and row\n\t\t// names, which may carry the same tokens as `columns` / `rows`.\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([key, item]) => [\n\t\t\t\tapplyReplacements(key, replacements, resolveAt),\n\t\t\t\treplaceWorkflowVariablesInValue(item, replacements, resolveAt),\n\t\t\t]),\n\t\t);\n\t}\n\n\treturn value;\n}\n\nfunction resolveWorkflowVariables(\n\tinput: string,\n\treplacements: VariableReplacement[],\n\tresolveAt: \"creation\" | \"execution\",\n): string {\n\treturn applyReplacements(input, replacements, resolveAt);\n}\n\nfunction validateTableFormatMap(\n\tblockId: string,\n\tfield: \"columnFormats\" | \"rowFormats\",\n\tformats: unknown,\n): void {\n\tif (formats && (typeof formats !== \"object\" || Array.isArray(formats))) {\n\t\tthrow new AinHttpError(\n\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t`Table block \"${blockId}\" must use ${field}: Record<string, object>.`,\n\t\t);\n\t}\n\n\tfor (const [key, format] of Object.entries(\n\t\t(formats || {}) as Record<string, unknown>,\n\t)) {\n\t\tif (!format || typeof format !== \"object\" || Array.isArray(format)) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${blockId}\" ${field}.${key} must be an object.`,\n\t\t\t);\n\t\t}\n\t\tconst candidate = format as WorkflowTableColumnFormat;\n\n\t\tif (\n\t\t\tcandidate.kind &&\n\t\t\t![\"auto\", \"text\", \"number\", \"currency\", \"percent\"].includes(\n\t\t\t\tString(candidate.kind),\n\t\t\t)\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${blockId}\" ${field}.${key}.kind is invalid.`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tcandidate.grouping !== undefined &&\n\t\t\ttypeof candidate.grouping !== \"boolean\"\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${blockId}\" ${field}.${key}.grouping must be boolean.`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tcandidate.decimals !== undefined &&\n\t\t\t(typeof candidate.decimals !== \"number\" ||\n\t\t\t\t!Number.isFinite(candidate.decimals))\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${blockId}\" ${field}.${key}.decimals must be a number.`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const stringKey of [\"prefix\", \"suffix\", \"nullDisplay\"] as const) {\n\t\t\tconst value = candidate[stringKey];\n\t\t\tif (value !== undefined && typeof value !== \"string\") {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Table block \"${blockId}\" ${field}.${key}.${stringKey} must be a string.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function validateWorkflowDefinition(\n\tdefinition?: WorkflowDefinition,\n): WorkflowDefinition | undefined {\n\tif (!definition) {\n\t\treturn undefined;\n\t}\n\n\tif (!Array.isArray(definition.tasks)) {\n\t\tthrow new AinHttpError(\n\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\"Workflow definition.tasks must be an array.\",\n\t\t);\n\t}\n\n\tfor (const [index, task] of definition.tasks.entries()) {\n\t\tif (typeof task.taskId !== \"string\" || !task.taskId.trim()) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Workflow task at index ${index} must use a non-empty taskId string.`,\n\t\t\t);\n\t\t}\n\n\t\tif (task.title !== undefined && typeof task.title !== \"string\") {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Task \"${task.taskId}\" title must be a string.`,\n\t\t\t);\n\t\t}\n\n\t\tif (typeof task.prompt !== \"string\" || !task.prompt.trim()) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Task \"${task.taskId}\" must use a non-empty prompt string.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (!Array.isArray(definition.response?.blocks)) {\n\t\tthrow new AinHttpError(\n\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\"Workflow definition.response.blocks must be an array.\",\n\t\t);\n\t}\n\n\tfor (const block of definition.response.blocks) {\n\t\tif (block.type === \"heading\") {\n\t\t\tif (typeof block.text !== \"string\" || !block.text.trim()) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Heading block \"${block.blockId}\" must use a non-empty text string.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tblock.level !== undefined &&\n\t\t\t\tblock.level !== 1 &&\n\t\t\t\tblock.level !== 2 &&\n\t\t\t\tblock.level !== 3\n\t\t\t) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Heading block \"${block.blockId}\" level must be 1, 2, or 3.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (\n\t\t\tblock.type === \"text\" &&\n\t\t\tblock.sourceBlockIds &&\n\t\t\t(!Array.isArray(block.sourceBlockIds) ||\n\t\t\t\tblock.sourceBlockIds.some((blockId) => typeof blockId !== \"string\"))\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Text block \"${block.blockId}\" must use sourceBlockIds: string[].`,\n\t\t\t);\n\t\t}\n\n\t\tif (block.type === \"graph\") {\n\t\t\tconst graphType = (block as { graphType?: unknown }).graphType;\n\t\t\tif (graphType !== \"xychart-beta\" && graphType !== \"pie\") {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Graph block \"${block.blockId}\" must declare graphType as \"xychart-beta\" or \"pie\".`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (typeof block.prompt !== \"string\" || !block.prompt.trim()) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Graph block \"${block.blockId}\" must use a non-empty prompt string.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (block.title !== undefined && typeof block.title !== \"string\") {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Graph block \"${block.blockId}\" title must be a string.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tblock.sourceTaskIds &&\n\t\t\t\t(!Array.isArray(block.sourceTaskIds) ||\n\t\t\t\t\tblock.sourceTaskIds.some((taskId) => typeof taskId !== \"string\"))\n\t\t\t) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Graph block \"${block.blockId}\" must use sourceTaskIds: string[].`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tblock.sourceBlockIds &&\n\t\t\t\t(!Array.isArray(block.sourceBlockIds) ||\n\t\t\t\t\tblock.sourceBlockIds.some((blockId) => typeof blockId !== \"string\"))\n\t\t\t) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Graph block \"${block.blockId}\" must use sourceBlockIds: string[].`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tblock.graphType === \"pie\" &&\n\t\t\t\tblock.showData !== undefined &&\n\t\t\t\ttypeof block.showData !== \"boolean\"\n\t\t\t) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Graph block \"${block.blockId}\" showData must be boolean.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (block.type !== \"table\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (block.layout !== \"records\" && block.layout !== \"matrix\") {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${block.blockId}\" must declare layout as \"records\" or \"matrix\".`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\t!Array.isArray(block.columns) ||\n\t\t\tblock.columns.length === 0 ||\n\t\t\tblock.columns.some((column) => typeof column !== \"string\")\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${block.blockId}\" must use columns: string[].`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tblock.layout === \"matrix\" &&\n\t\t\t(!Array.isArray(block.rows) ||\n\t\t\t\tblock.rows.length === 0 ||\n\t\t\t\tblock.rows.some((row) => typeof row !== \"string\"))\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Matrix table block \"${block.blockId}\" must use rows: string[].`,\n\t\t\t);\n\t\t}\n\n\t\tif (block.unit !== undefined && typeof block.unit !== \"string\") {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${block.blockId}\" unit must be a string.`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tblock.formulas &&\n\t\t\t(!Array.isArray(block.formulas) ||\n\t\t\t\tblock.formulas.some((formula) => typeof formula !== \"string\"))\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${block.blockId}\" must use formulas: string[].`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const key of [\"hiddenRows\", \"hiddenColumns\"] as const) {\n\t\t\tconst value = block[key];\n\t\t\tif (\n\t\t\t\tvalue &&\n\t\t\t\t(!Array.isArray(value) ||\n\t\t\t\t\tvalue.some((item) => typeof item !== \"string\"))\n\t\t\t) {\n\t\t\t\tthrow new AinHttpError(\n\t\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t\t`Table block \"${block.blockId}\" must use ${key}: string[].`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tvalidateTableFormatMap(block.blockId, \"columnFormats\", block.columnFormats);\n\t\tvalidateTableFormatMap(block.blockId, \"rowFormats\", block.rowFormats);\n\n\t\tif (\n\t\t\tblock.rowFormats &&\n\t\t\tObject.keys(block.rowFormats).length &&\n\t\t\tblock.layout !== \"matrix\"\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${block.blockId}\" supports rowFormats only with layout: matrix.`,\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tblock.sourceTaskIds &&\n\t\t\t(!Array.isArray(block.sourceTaskIds) ||\n\t\t\t\tblock.sourceTaskIds.some((taskId) => typeof taskId !== \"string\"))\n\t\t) {\n\t\t\tthrow new AinHttpError(\n\t\t\t\tStatusCodes.BAD_REQUEST,\n\t\t\t\t`Table block \"${block.blockId}\" must use sourceTaskIds: string[].`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn definition;\n}\n\nfunction normalizeVariableType(\n\ttype: WorkflowVariable[\"type\"],\n): WorkflowVariable[\"type\"] {\n\treturn type === \"dropdown\" ? \"select\" : type;\n}\n\nfunction normalizeWorkflowVariablesRecord(\n\tvariables?: Record<string, WorkflowVariable>,\n): Record<string, WorkflowVariable> | undefined {\n\tif (!variables) {\n\t\treturn undefined;\n\t}\n\n\treturn Object.fromEntries(\n\t\tObject.entries(variables).map(([key, variable]) => [\n\t\t\tkey,\n\t\t\t{\n\t\t\t\t...variable,\n\t\t\t\ttype: normalizeVariableType(variable.type),\n\t\t\t},\n\t\t]),\n\t);\n}\n\nfunction resolveTemplateValue(value: unknown, timezone?: string): unknown {\n\tif (typeof value === \"string\") {\n\t\treturn resolveTemplateString(value, timezone);\n\t}\n\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => resolveTemplateValue(item, timezone));\n\t}\n\n\tif (value && typeof value === \"object\") {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([key, item]) => [\n\t\t\t\tresolveTemplateString(key, timezone),\n\t\t\t\tresolveTemplateValue(item, timezone),\n\t\t\t]),\n\t\t);\n\t}\n\n\treturn value;\n}\n\nexport class WorkflowVariableResolver {\n\tnormalizeDefinition(\n\t\tdefinition?: WorkflowDefinition,\n\t): WorkflowDefinition | undefined {\n\t\treturn validateWorkflowDefinition(definition);\n\t}\n\n\tnormalizeVariables(\n\t\tvariables?: Record<string, WorkflowVariable>,\n\t): Record<string, WorkflowVariable> | undefined {\n\t\treturn normalizeWorkflowVariablesRecord(variables);\n\t}\n\n\tresolveForCreation(workflow: WorkflowTextFields): {\n\t\tcontent: string;\n\t\ttitle: string;\n\t\tdefinition?: WorkflowDefinition;\n\t} {\n\t\tlet { content, title } = workflow;\n\t\tlet definition: WorkflowDefinition | undefined = workflow.definition;\n\t\tconst normalizedVariables = normalizeWorkflowVariablesRecord(\n\t\t\tworkflow.variables,\n\t\t);\n\n\t\tif (!workflow.variableValues || !normalizedVariables) {\n\t\t\treturn {\n\t\t\t\tcontent,\n\t\t\t\ttitle,\n\t\t\t\tdefinition: validateWorkflowDefinition(definition),\n\t\t\t};\n\t\t}\n\n\t\tconst replacements = buildVariableReplacements(\n\t\t\tworkflow.variableValues,\n\t\t\tnormalizedVariables,\n\t\t);\n\n\t\tcontent = resolveWorkflowVariables(content, replacements, \"creation\");\n\t\ttitle = resolveWorkflowVariables(title, replacements, \"creation\");\n\n\t\tdefinition = replaceWorkflowVariablesInValue(\n\t\t\tdefinition,\n\t\t\treplacements,\n\t\t\t\"creation\",\n\t\t) as WorkflowDefinition | undefined;\n\n\t\treturn {\n\t\t\tcontent,\n\t\t\ttitle,\n\t\t\tdefinition: validateWorkflowDefinition(definition),\n\t\t};\n\t}\n\n\tresolveForExecution(\n\t\tworkflow: WorkflowTextFields,\n\t\texecutionVariables?: Record<string, string>,\n\t): {\n\t\tquery: string;\n\t\tdisplayQuery: string;\n\t\tdefinition?: WorkflowDefinition;\n\t} {\n\t\treturn this.resolveExecutionLike(workflow, executionVariables, false);\n\t}\n\n\t/**\n\t * Resolves a workflow for filling a document slot.\n\t *\n\t * Unlike {@link resolveForExecution}, the document context has no\n\t * creation/execution distinction: every variable value is already decided\n\t * (entered in the document-creation dialog or fixed by the workplace) and\n\t * stored on the slot binding. So all provided values are substituted\n\t * regardless of each variable's declared `resolveAt`, then built-in template\n\t * tokens (e.g. `{{today}}`) are resolved. This does NOT change how standalone\n\t * workflow execution resolves variables.\n\t *\n\t * Empty/whitespace-only values mean \"not entered\" (slot bindings persist\n\t * such keys for display) and are dropped here so they don't override the\n\t * workflow's own `variableValues` defaults with blanks.\n\t */\n\tresolveForDocumentFill(\n\t\tworkflow: WorkflowTextFields,\n\t\tprovidedVariables?: Record<string, string>,\n\t): {\n\t\tquery: string;\n\t\tdisplayQuery: string;\n\t\tdefinition?: WorkflowDefinition;\n\t} {\n\t\tconst nonEmptyVariables = providedVariables\n\t\t\t? Object.fromEntries(\n\t\t\t\t\tObject.entries(providedVariables).filter(\n\t\t\t\t\t\t([, value]) => value.trim() !== \"\",\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t: undefined;\n\t\treturn this.resolveExecutionLike(workflow, nonEmptyVariables, true);\n\t}\n\n\t/**\n\t * Shared execution-time variable substitution. Only `execution`-scoped\n\t * replacements apply, EXCEPT when `forceResolveAt` is true (document-slot\n\t * fills), where every provided value is applied regardless of its declared\n\t * `resolveAt`. Built-in template tokens (e.g. `{{today}}`) are always resolved.\n\t */\n\tprivate resolveExecutionLike(\n\t\tworkflow: WorkflowTextFields,\n\t\tprovidedVariables: Record<string, string> | undefined,\n\t\tforceResolveAt: boolean,\n\t): {\n\t\tquery: string;\n\t\tdisplayQuery: string;\n\t\tdefinition?: WorkflowDefinition;\n\t} {\n\t\tconst { timezone } = workflow;\n\t\tlet query = workflow.content;\n\t\tlet displayQuery = workflow.title;\n\t\tlet definition: WorkflowDefinition | undefined = workflow.definition;\n\t\tconst normalizedVariables = normalizeWorkflowVariablesRecord(\n\t\t\tworkflow.variables,\n\t\t);\n\t\tconst mergedVariables = {\n\t\t\t...(workflow.variableValues || {}),\n\t\t\t...(providedVariables || {}),\n\t\t};\n\n\t\tif (Object.keys(mergedVariables).length > 0) {\n\t\t\tconst resolvedVars = resolveTemplateRecord(mergedVariables, timezone);\n\t\t\tlet replacements = buildVariableReplacements(\n\t\t\t\tresolvedVars,\n\t\t\t\tnormalizedVariables,\n\t\t\t);\n\t\t\tif (forceResolveAt) {\n\t\t\t\treplacements = replacements.map((replacement) => ({\n\t\t\t\t\t...replacement,\n\t\t\t\t\tresolveAt: \"execution\" as const,\n\t\t\t\t}));\n\t\t\t}\n\t\t\tquery = resolveWorkflowVariables(query, replacements, \"execution\");\n\t\t\tdisplayQuery = resolveWorkflowVariables(\n\t\t\t\tdisplayQuery,\n\t\t\t\treplacements,\n\t\t\t\t\"execution\",\n\t\t\t);\n\t\t\tdefinition = replaceWorkflowVariablesInValue(\n\t\t\t\tdefinition,\n\t\t\t\treplacements,\n\t\t\t\t\"execution\",\n\t\t\t) as WorkflowDefinition | undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tquery: resolveTemplateString(query, timezone),\n\t\t\tdisplayQuery: resolveTemplateString(displayQuery, timezone),\n\t\t\tdefinition: validateWorkflowDefinition(\n\t\t\t\tresolveTemplateValue(definition, timezone) as\n\t\t\t\t\t| WorkflowDefinition\n\t\t\t\t\t| undefined,\n\t\t\t),\n\t\t};\n\t}\n}\n"]}