{"version":3,"sources":["/Users/shyun/comcom/ain-enterprise/ain-adk/dist/cjs/chunk-WS4POIFU.cjs","../../src/services/workflow-variable-extraction.service.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACAA,SAAS,gBAAA,CAAiB,GAAA,EAAa,IAAA,EAAgC;AAItE,EAAA,MAAM,MAAA,EACL,IAAA,CAAK,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,IAAA,EAAM,CAAA,iBAAA,EAAoB,IAAA,CAAK,EAAE,CAAA,CAAA,EAAA,EAAM,EAAA;AAC/D,EAAA,MAAM,MAAA,EAAQ,CAAC,CAAA,QAAA,EAAW,GAAG,CAAA,GAAA,EAAM,IAAA,CAAK,IAAI,CAAA,SAAA,EAAO,IAAA,CAAK,KAAK,CAAA,EAAA;AAGvD,EAAA;AAEC,IAAA;AAEE,MAAA;AAER,IAAA;AACD,EAAA;AACgC,EAAA;AACuB,IAAA;AACvD,EAAA;AACgC,EAAA;AACzB,IAAA;AACL,MAAA;AACD,IAAA;AACD,EAAA;AAC4B,EAAA;AACuB,IAAA;AACnD,EAAA;AACsB,EAAA;AACvB;AAMU;AACF,EAAA;AAAA;AAEsC,gBAAA;AAAA;AAAA;AAGhC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAAA;AAsBd;AAOC;AAEyD;AACH,EAAA;AACI,IAAA;AACjD,MAAA;AACR,IAAA;AACD,EAAA;AACO,EAAA;AACR;AAE+C;AACtC,EAAA;AAE8B,EAAA;AAClB,IAAA;AACpB,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc+C,EAAA;AACN,IAAA;AACd,IAAA;AAClB,MAAA;AACR,IAAA;AAEI,IAAA;AACmC,MAAA;AACM,MAAA;AACjC,QAAA;AACV,MAAA;AACoB,MAAA;AACsC,QAAA;AAC1D,QAAA;AACA,QAAA;AACD,MAAA;AAEgD,MAAA;AACA,MAAA;AACf,QAAA;AAChC,QAAA;AACA,MAAA;AACoC,MAAA;AACpC,QAAA;AACiC,QAAA;AAClC,MAAA;AACuB,MAAA;AACf,QAAA;AACR,MAAA;AAE0C,MAAA;AACF,MAAA;AACL,MAAA;AAGS,QAAA;AACK,QAAA;AAC/C,UAAA;AACD,QAAA;AACqC,QAAA;AACpC,UAAA;AACD,QAAA;AAGC,QAAA;AAGA,UAAA;AACD,QAAA;AACyB,QAAA;AAC1B,MAAA;AAEsC,MAAA;AAC9B,QAAA;AACR,MAAA;AAE+D,MAAA;AAC/B,QAAA;AAC/B,MAAA;AACM,MAAA;AACQ,IAAA;AACA,MAAA;AACd,QAAA;AACQ,QAAA;AACT,MAAA;AACO,MAAA;AACR,IAAA;AACD,EAAA;AACD;ADrCqE;AACA;AACA;AACA","file":"/Users/shyun/comcom/ain-enterprise/ain-adk/dist/cjs/chunk-WS4POIFU.cjs","sourcesContent":[null,"import type { ModelModule } from \"@/modules\";\nimport type { WorkflowVariable } from \"@/types/memory\";\nimport { loggers } from \"@/utils/logger\";\n\nfunction describeVariable(key: string, spec: WorkflowVariable): string {\n\t// The JSON key MUST be the variables-record key: the resolver looks\n\t// values up by record key (and only then derives {{key}}/{{id}} tokens),\n\t// so values keyed by spec.id alone never substitute {{record_key}} tokens.\n\tconst alias =\n\t\tspec.id && spec.id !== key ? `, also known as \"${spec.id}\"` : \"\";\n\tconst lines = [`- key: \"${key}\" (${spec.type}) — ${spec.label}${alias}`];\n\tif (\n\t\t(spec.type === \"dropdown\" || spec.type === \"select\") &&\n\t\tspec.options?.length\n\t) {\n\t\tlines.push(\n\t\t\t`  value MUST be exactly one of: ${spec.options\n\t\t\t\t.map((option) => `\"${option}\"`)\n\t\t\t\t.join(\", \")}`,\n\t\t);\n\t}\n\tif (spec.type === \"date_range\") {\n\t\tlines.push('  value format: \"YYYY-MM-DD ~ YYYY-MM-DD\"');\n\t}\n\tif (spec.type === \"date_parts\") {\n\t\tlines.push(\n\t\t\t'  value format: \"YYYY-MM-DD\" (use \"YYYY-MM\" or \"YYYY\" if the query is less specific)',\n\t\t);\n\t}\n\tif (spec.type === \"number\") {\n\t\tlines.push(\"  value: the number as a plain string\");\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction buildExtractionPrompt(\n\tvariableList: string,\n\ttoday: string,\n\ttimezone: string,\n): string {\n\treturn `You extract workflow variable values from a user's request.\n\nToday's date is ${today} (timezone: ${timezone}).\n\nVariables to extract:\n${variableList}\n\nFor RELATIVE date expressions, output built-in tokens instead of computing\ndates yourself — the system resolves them deterministically in the\nworkflow's timezone. Available tokens: {{today}}, {{yesterday}},\n{{tomorrow}}, {{today+N}}, {{today-N}}, {{startOfWeek}}, {{endOfWeek}},\n{{startOfMonth}}, {{endOfMonth}}, {{year}}, {{month}}, {{day}}.\nExamples:\n- \"오늘\" → \"{{today}}\"\n- \"지난 일주일\" / \"최근 7일\" → \"{{today-7}} ~ {{yesterday}}\"\n- \"이번 주\" → \"{{startOfWeek}} ~ {{endOfWeek}}\"\n- \"이번 달\" → \"{{startOfMonth}} ~ {{endOfMonth}}\"\nOnly when the request names dates the tokens cannot express (e.g.\n\"7월 20일부터 26일까지\", \"지난주 월요일부터 금요일까지\"), compute absolute\ndates against today's date and output \"YYYY-MM-DD\" literals. Never invent\ntoken names beyond the list above.\n\nRespond with a single JSON object mapping variable keys to string values.\nRules:\n- Include a variable ONLY if its value is clearly stated or derivable from the request. If unsure, OMIT the key entirely — never guess.\n- All values must be strings in the format specified per variable.\n- Respond with the JSON object only, no other text.`;\n}\n\n/** Token grammar of src/utils/template-variables.ts (resolveVariable). An\n * unknown token would survive resolution as a literal \"{{...}}\" string in\n * the task prompt, so values containing one are rejected here and fall\n * back to the workflow's stored defaults. */\nconst KNOWN_TEMPLATE_TOKEN_PATTERN =\n\t/^(?:today|yesterday|tomorrow|now|year|month|day|startOfWeek|endOfWeek|startOfMonth|endOfMonth|today[+-]\\d+|(?:year|month|day)[+-]\\d+)(?:\\|[^}]+)?$/;\n\nfunction hasUnknownTemplateTokens(value: string): boolean {\n\tfor (const match of value.matchAll(/\\{\\{(.+?)\\}\\}/g)) {\n\t\tif (!KNOWN_TEMPLATE_TOKEN_PATTERN.test(match[1].trim())) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport class WorkflowVariableExtractionService {\n\tprivate modelModule: ModelModule;\n\n\tconstructor(modelModule: ModelModule) {\n\t\tthis.modelModule = modelModule;\n\t}\n\n\t/**\n\t * Extracts workflow variable values from a natural-language query with a\n\t * single non-streaming LLM call. Returns only values that survive\n\t * validation (dropdown/select values must match options); anything\n\t * missing falls back to the workflow's stored variableValues at resolve\n\t * time. Fails open (returns undefined) on any model or parse error so\n\t * intent fulfillment never breaks on extraction.\n\t */\n\tasync extractFromQuery(\n\t\tvariables: Record<string, WorkflowVariable>,\n\t\tquery: string,\n\t\ttimezone?: string,\n\t): Promise<Record<string, string> | undefined> {\n\t\tconst entries = Object.entries(variables);\n\t\tif (entries.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst effectiveTimezone = timezone || \"Asia/Seoul\";\n\t\t\tconst today = new Date().toLocaleDateString(\"en-CA\", {\n\t\t\t\ttimeZone: effectiveTimezone,\n\t\t\t});\n\t\t\tconst systemPrompt = buildExtractionPrompt(\n\t\t\t\tentries.map(([key, spec]) => describeVariable(key, spec)).join(\"\\n\"),\n\t\t\t\ttoday,\n\t\t\t\teffectiveTimezone,\n\t\t\t);\n\n\t\t\tconst modelInstance = this.modelModule.getModel();\n\t\t\tconst messages = modelInstance.generateMessages({\n\t\t\t\tquery: `User request: \"\"\"${query}\"\"\"`,\n\t\t\t\tsystemPrompt,\n\t\t\t});\n\t\t\tconst response = await modelInstance.fetch(\n\t\t\t\tmessages,\n\t\t\t\tthis.modelModule.getModelOptions(),\n\t\t\t);\n\t\t\tif (!response.content) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst parsed = JSON.parse(response.content) as Record<string, unknown>;\n\t\t\tconst values: Record<string, string> = {};\n\t\t\tfor (const [key, spec] of entries) {\n\t\t\t\t// Prefer the record key; accept the spec id as a fallback in case\n\t\t\t\t// the model answered with the alias.\n\t\t\t\tconst value = parsed[key] ?? parsed[spec.id];\n\t\t\t\tif (typeof value !== \"string\" || !value.trim()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (hasUnknownTemplateTokens(value)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\t(spec.type === \"dropdown\" || spec.type === \"select\") &&\n\t\t\t\t\tspec.options?.length &&\n\t\t\t\t\t!spec.options.includes(value.trim())\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tvalues[key] = value.trim();\n\t\t\t}\n\n\t\t\tif (Object.keys(values).length === 0) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tloggers.intent.info(\"Extracted workflow variables from query\", {\n\t\t\t\tvariableIds: Object.keys(values),\n\t\t\t});\n\t\t\treturn values;\n\t\t} catch (error) {\n\t\t\tloggers.intent.warn(\n\t\t\t\t\"Workflow variable extraction failed; using stored defaults\",\n\t\t\t\t{ error },\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}