{"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../../src/core/workspace/planner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC/B,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAoBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,eAAe,GAAG,aAAa,CAuDlF;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAExF","sourcesContent":["/**\n * Deterministic query planner.\n *\n * Classifies a retrieval query into a mode and selects bounded candidate\n * generators. Model assistance is optional and never required; the default is a\n * deterministic rule-based planner. The planner cannot expand workspace scope.\n */\n\nimport { searchSymbolName } from \"./lexical.js\";\nimport type { WorkspaceDb } from \"./storage.js\";\nimport type { RetrievalPlan } from \"./types.js\";\n\nexport interface PlannerInput {\n\tquery: string;\n\tlanguageFilters?: string[];\n\tfileClassFilters?: string[];\n\tpathFilter?: string;\n\tcurrentFile?: string;\n\tcurrentSymbol?: string;\n\ttaskRole?: string;\n\tmaximumResults?: number;\n\tmaximumContextTokens?: number;\n\tembeddingAvailable?: boolean;\n}\n\nexport interface PlanningContext {\n\tembeddingAvailable: boolean;\n}\n\nconst IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst FLOW_WORDS = /(how|flow|sequence|call|relationship|depends|between|and|involves)/i;\nconst DOC_WORDS = /(document|readme|explain|usage|guide|doc)/i;\nconst TEST_WORDS = /(test|spec|verify|protect|regression)/i;\nconst CONFIG_WORDS = /(config|setting|option|environment|enable|disable)/i;\nconst HISTORY_WORDS = /(change|history|recent|regress|commit|modified|changed)/i;\n\nfunction classifyMode(q: string): RetrievalPlan[\"mode\"] {\n\tif (IDENTIFIER_RE.test(q.trim())) return \"exact_identifier\";\n\tif (CONFIG_WORDS.test(q)) return \"configuration\";\n\tif (HISTORY_WORDS.test(q)) return \"historical_change\";\n\tif (TEST_WORDS.test(q)) return \"test_discovery\";\n\tif (DOC_WORDS.test(q)) return \"documentation\";\n\tif (FLOW_WORDS.test(q)) return \"flow_investigation\";\n\tif (/\\bsymbol|class|function|method|interface|typedef/.test(q)) return \"symbol_lookup\";\n\treturn \"semantic_concept\";\n}\n\nexport function planQuery(input: PlannerInput, ctx: PlanningContext): RetrievalPlan {\n\tconst query = input.query.trim();\n\tconst mode = classifyMode(query);\n\tconst maxResults = Math.max(1, input.maximumResults ?? 50);\n\tconst embeddingAvailable = ctx.embeddingAvailable && mode !== \"exact_identifier\";\n\n\tconst generators: Array<{ kind: string; limit: number; filters: Record<string, unknown> }> = [];\n\n\tswitch (mode) {\n\t\tcase \"exact_identifier\":\n\t\t\tgenerators.push({ kind: \"symbol\", limit: maxResults, filters: { name: query } });\n\t\t\tgenerators.push({ kind: \"lexical\", limit: maxResults, filters: { exact: true } });\n\t\t\tgenerators.push({ kind: \"path\", limit: 10, filters: { path: query } });\n\t\t\tbreak;\n\t\tcase \"symbol_lookup\":\n\t\t\tgenerators.push({ kind: \"symbol\", limit: maxResults, filters: { name: query } });\n\t\t\tgenerators.push({ kind: \"lexical\", limit: maxResults, filters: {} });\n\t\t\tif (embeddingAvailable) generators.push({ kind: \"semantic\", limit: maxResults, filters: {} });\n\t\t\tbreak;\n\t\tcase \"flow_investigation\":\n\t\t\tgenerators.push({ kind: \"lexical\", limit: maxResults, filters: {} });\n\t\t\tgenerators.push({ kind: \"symbol\", limit: maxResults, filters: {} });\n\t\t\tif (embeddingAvailable) generators.push({ kind: \"semantic\", limit: maxResults, filters: {} });\n\t\t\tbreak;\n\t\tcase \"documentation\":\n\t\tcase \"test_discovery\":\n\t\tcase \"configuration\":\n\t\tcase \"historical_change\":\n\t\t\tgenerators.push({\n\t\t\t\tkind: \"lexical\",\n\t\t\t\tlimit: maxResults,\n\t\t\t\tfilters: {\n\t\t\t\t\tfileClass: mode === \"documentation\" ? \"documentation\" : mode === \"test_discovery\" ? \"test\" : undefined,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (mode === \"test_discovery\") generators.push({ kind: \"symbol\", limit: maxResults, filters: {} });\n\t\t\tif (embeddingAvailable) generators.push({ kind: \"semantic\", limit: maxResults, filters: {} });\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t// semantic_concept / mixed\n\t\t\tgenerators.push({ kind: \"lexical\", limit: maxResults, filters: {} });\n\t\t\tif (embeddingAvailable) generators.push({ kind: \"semantic\", limit: maxResults, filters: {} });\n\t\t\tgenerators.push({ kind: \"path\", limit: 10, filters: {} });\n\t\t\tbreak;\n\t}\n\n\treturn {\n\t\tqueryId: `q_${Math.random().toString(36).slice(2, 12)}`,\n\t\tmode,\n\t\tnormalizedQuery: query.toLowerCase(),\n\t\tgenerators,\n\t\treranker: \"deterministic_heuristic\",\n\t\tmaximumResults: maxResults,\n\t\tmaximumContextTokens: input.maximumContextTokens,\n\t};\n}\n\n/** Quick symbol-existence probe to inform mode decisions in downstream code. */\nexport function probeSymbol(db: WorkspaceDb, generationId: string, name: string): boolean {\n\treturn searchSymbolName(db, generationId, name, 5).length > 0;\n}\n"]}