java-codebase-rag 0.9.4__py3-none-any.whl → 0.9.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. java_codebase_rag/absence/__init__.py +0 -0
  2. java_codebase_rag/absence/absence_diagnosis.py +700 -0
  3. java_codebase_rag/absence/absence_types.py +124 -0
  4. java_codebase_rag/absence/absence_vocab.py +455 -0
  5. java_codebase_rag/analysis/__init__.py +0 -0
  6. pr_analysis.py → java_codebase_rag/analysis/pr_analysis.py +1 -1
  7. resolve_service.py → java_codebase_rag/analysis/resolve_service.py +73 -6
  8. java_codebase_rag/ast/__init__.py +0 -0
  9. ast_java.py → java_codebase_rag/ast/ast_java.py +5 -5
  10. java_codebase_rag/cli.py +13 -18
  11. java_codebase_rag/config.py +116 -0
  12. java_codebase_rag/graph/__init__.py +0 -0
  13. build_ast_graph.py → java_codebase_rag/graph/build_ast_graph.py +89 -11
  14. graph_enrich.py → java_codebase_rag/graph/graph_enrich.py +248 -3
  15. graph_types.py → java_codebase_rag/graph/graph_types.py +6 -2
  16. java_ontology.py → java_codebase_rag/graph/java_ontology.py +1 -1
  17. ladybug_queries.py → java_codebase_rag/graph/ladybug_queries.py +6 -6
  18. java_codebase_rag/index/__init__.py +0 -0
  19. java_index_flow_lancedb.py → java_codebase_rag/index/java_index_flow_lancedb.py +30 -10
  20. java_codebase_rag/install_data/__init__.py +0 -0
  21. java_codebase_rag/jrag.py +71 -16
  22. java_codebase_rag/jrag_envelope.py +13 -4
  23. java_codebase_rag/jrag_hints.py +1 -1
  24. java_codebase_rag/jrag_render.py +67 -3
  25. java_codebase_rag/mcp/__init__.py +0 -0
  26. mcp_hints.py → java_codebase_rag/mcp/mcp_hints.py +1 -1
  27. mcp_v2.py → java_codebase_rag/mcp/mcp_v2.py +280 -81
  28. server.py → java_codebase_rag/mcp/server.py +138 -54
  29. java_codebase_rag/pipeline.py +26 -7
  30. java_codebase_rag/search/__init__.py +0 -0
  31. search_lancedb.py → java_codebase_rag/search/search_lancedb.py +53 -314
  32. java_codebase_rag/search/search_lexical.py +329 -0
  33. java_codebase_rag/search/search_scoring.py +338 -0
  34. {java_codebase_rag-0.9.4.dist-info → java_codebase_rag-0.9.6.dist-info}/METADATA +2 -2
  35. java_codebase_rag-0.9.6.dist-info/RECORD +57 -0
  36. {java_codebase_rag-0.9.4.dist-info → java_codebase_rag-0.9.6.dist-info}/entry_points.txt +1 -1
  37. java_codebase_rag-0.9.6.dist-info/top_level.txt +1 -0
  38. java_codebase_rag-0.9.4.dist-info/RECORD +0 -44
  39. java_codebase_rag-0.9.4.dist-info/top_level.txt +0 -19
  40. /brownfield_events.py → /java_codebase_rag/ast/brownfield_events.py +0 -0
  41. /chunk_heuristics.py → /java_codebase_rag/ast/chunk_heuristics.py +0 -0
  42. /path_filtering.py → /java_codebase_rag/graph/path_filtering.py +0 -0
  43. /java_index_v1_common.py → /java_codebase_rag/index/java_index_v1_common.py +0 -0
  44. /index_common.py → /java_codebase_rag/search/index_common.py +0 -0
  45. {java_codebase_rag-0.9.4.dist-info → java_codebase_rag-0.9.6.dist-info}/WHEEL +0 -0
  46. {java_codebase_rag-0.9.4.dist-info → java_codebase_rag-0.9.6.dist-info}/licenses/LICENSE +0 -0
@@ -6,11 +6,14 @@ by the CLI layer. Provides resolve_v2(identifier, hint_kind, graph) -> ResolveOu
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from typing import Literal
9
+ from typing import Any, Literal
10
10
 
11
11
  from pydantic import BaseModel, ConfigDict, Field
12
12
 
13
- from graph_types import (
13
+ from java_codebase_rag.absence.absence_types import AbsenceDiagnosis
14
+ from java_codebase_rag.absence.absence_diagnosis import diagnose
15
+ from java_codebase_rag.absence.absence_vocab import get_vocabulary_index
16
+ from java_codebase_rag.graph.graph_types import (
14
17
  NodeRef,
15
18
  StructuredHint,
16
19
  _hints_or_skip,
@@ -18,9 +21,9 @@ from graph_types import (
18
21
  _to_structured_hints,
19
22
  set_hints_enabled,
20
23
  )
21
- from java_ontology import ResolveReason
22
- from ladybug_queries import LadybugGraph
23
- from mcp_hints import MCP_HINTS_STRUCTURED_FIELD_DESCRIPTION
24
+ from java_codebase_rag.graph.java_ontology import ResolveReason
25
+ from java_codebase_rag.graph.ladybug_queries import LadybugGraph
26
+ from java_codebase_rag.mcp.mcp_hints import MCP_HINTS_STRUCTURED_FIELD_DESCRIPTION
24
27
 
25
28
  __all__ = [
26
29
  "resolve_v2",
@@ -28,6 +31,7 @@ __all__ = [
28
31
  "ResolveCandidate",
29
32
  "ResolveStatus",
30
33
  "set_hints_enabled",
34
+ "set_absence_config",
31
35
  ]
32
36
 
33
37
 
@@ -35,6 +39,35 @@ ResolveStatus = Literal["one", "many", "none"]
35
39
 
36
40
  _RESOLVE_CANDIDATE_CAP = 10
37
41
 
42
+ # Module-level holder for absence diagnosis config (set by server.py)
43
+ _absence_config: Any = None
44
+
45
+
46
+ def set_absence_config(cfg: Any) -> None:
47
+ """Set the global absence diagnosis config for resolve service.
48
+
49
+ Mirrors set_hints_enabled: called from server.py to make cfg reachable
50
+ in resolve functions without threading it through every signature.
51
+ """
52
+ global _absence_config
53
+ _absence_config = cfg
54
+
55
+
56
+ def _get_absence_config() -> Any:
57
+ """Get the absence diagnosis config, with safe fallback.
58
+
59
+ Returns the module-level config if set; otherwise falls back to a
60
+ default config (for direct tool calls in tests without server init).
61
+ """
62
+ if _absence_config is not None:
63
+ return _absence_config
64
+
65
+ # Fallback: resolve from cwd for direct test calls
66
+ from java_codebase_rag.config import resolve_operator_config
67
+ from pathlib import Path
68
+
69
+ return resolve_operator_config(source_root=Path.cwd())
70
+
38
71
  _RESOLVE_REASON_PRIORITY: dict[ResolveReason, int] = {
39
72
  "exact_id": 0,
40
73
  "exact_fqn": 1,
@@ -129,6 +162,7 @@ class ResolveOutput(BaseModel):
129
162
  resolved_identifier: str | None = None
130
163
  advisories: list[str] = Field(default_factory=list, description="Pure informational text with no tool call suggestion")
131
164
  hints_structured: list[StructuredHint] = Field(default_factory=list, description=MCP_HINTS_STRUCTURED_FIELD_DESCRIPTION)
165
+ absence: AbsenceDiagnosis | None = None
132
166
 
133
167
 
134
168
  def _resolve_validate_identifier(raw: str) -> tuple[str | None, str | None]:
@@ -566,6 +600,9 @@ def _resolve_finalize_success(
566
600
  trimmed: str,
567
601
  hint_kind: Literal["symbol", "route", "client", "producer"] | None,
568
602
  matches: list[ResolveCandidate],
603
+ graph: LadybugGraph | None = None,
604
+ microservice: str = "",
605
+ module: str = "",
569
606
  ) -> ResolveOutput:
570
607
  if not matches:
571
608
  out = ResolveOutput(
@@ -591,6 +628,28 @@ def _resolve_finalize_success(
591
628
  resolved_identifier=trimmed,
592
629
  )
593
630
 
631
+ # Absence diagnosis for empty results (status="none")
632
+ cfg = _get_absence_config()
633
+ diag: AbsenceDiagnosis | None = None
634
+ if not matches:
635
+ g = graph
636
+ vocab = get_vocabulary_index(g, cfg)
637
+ # Map hint_kind to filter_kind (symbol -> "symbol", etc.)
638
+ filter_kind = hint_kind if hint_kind in ("symbol", "route", "client", "producer") else None
639
+ # Build scope from microservice/module params
640
+ scope = {"microservice": microservice or "", "module": module or ""}
641
+ diag = diagnose(
642
+ tool="resolve",
643
+ query=trimmed,
644
+ filt=None,
645
+ filter_kind=filter_kind,
646
+ root_node=None,
647
+ scope=scope,
648
+ vocab=vocab,
649
+ graph=g,
650
+ cfg=cfg,
651
+ )
652
+
594
653
  path_prefix_seed, target_service_seed = _resolve_seeds_for_hints(trimmed)
595
654
  hint_payload = {
596
655
  "status": out.status,
@@ -604,6 +663,7 @@ def _resolve_finalize_success(
604
663
  out = out.model_copy(update={
605
664
  "advisories": raw_advisories,
606
665
  "hints_structured": _to_structured_hints(raw_struct),
666
+ "absence": diag,
607
667
  })
608
668
  _resolve_assert_invariants(out)
609
669
  return out
@@ -660,7 +720,14 @@ def resolve_v2(
660
720
  deduped = _resolve_dedupe_candidates(raw)
661
721
  ranked = _resolve_rank_candidates(deduped)
662
722
  capped = ranked[:_RESOLVE_CANDIDATE_CAP]
663
- return _resolve_finalize_success(trimmed, hint_kind, capped)
723
+ return _resolve_finalize_success(
724
+ trimmed,
725
+ hint_kind,
726
+ capped,
727
+ graph=g,
728
+ microservice=microservice,
729
+ module=module,
730
+ )
664
731
  except Exception as exc:
665
732
  out = ResolveOutput(
666
733
  success=False,
File without changes
@@ -20,7 +20,7 @@ from typing import Iterable
20
20
 
21
21
  import tree_sitter_java as _ts_java
22
22
 
23
- from brownfield_events import (
23
+ from java_codebase_rag.ast.brownfield_events import (
24
24
  emit_brownfield_exclusivity_shadowing,
25
25
  emit_brownfield_method_string_literal,
26
26
  )
@@ -84,7 +84,7 @@ _DTO_LOMBOK_ANNOTATIONS: frozenset[str] = frozenset({
84
84
  # Phase 11: `EDGE_SCHEMA` in `java_ontology.py` (canonical edge navigation schema; v14 re-index).
85
85
  # Phase 12: CALLS `callee_declaring_role`, supertype-walk dedup, pass3 unresolved counters (v15 re-index).
86
86
  # Bumps whenever extraction / enrichment semantics change.
87
- ONTOLOGY_VERSION = 17
87
+ ONTOLOGY_VERSION = 18
88
88
 
89
89
  ROLE_ANNOTATIONS: dict[str, str] = {
90
90
  # Spring Web
@@ -1617,7 +1617,7 @@ def _parse_codebase_http_client_annotation(
1617
1617
  val, vkind = _annotation_value(pairs["clientKind"], src)
1618
1618
  if val and vkind == "enum":
1619
1619
  kind_val = str(val)
1620
- from java_ontology import VALID_CLIENT_KINDS # deferred: java_ontology imports ast_java
1620
+ from java_codebase_rag.graph.java_ontology import VALID_CLIENT_KINDS # deferred: java_ontology imports ast_java
1621
1621
  if kind_val in VALID_CLIENT_KINDS:
1622
1622
  client_kind = kind_val
1623
1623
  else:
@@ -1697,7 +1697,7 @@ def _parse_codebase_producer_annotation(
1697
1697
  val, vkind = _annotation_value(kind_node, src)
1698
1698
  if val and vkind == "enum":
1699
1699
  kind_val = str(val)
1700
- from java_ontology import VALID_PRODUCER_KINDS # deferred: java_ontology imports ast_java
1700
+ from java_codebase_rag.graph.java_ontology import VALID_PRODUCER_KINDS # deferred: java_ontology imports ast_java
1701
1701
  if kind_val in VALID_PRODUCER_KINDS:
1702
1702
  client_kind = kind_val
1703
1703
  else:
@@ -1868,7 +1868,7 @@ def _collect_outgoing_calls(
1868
1868
  file_rel: str,
1869
1869
  ) -> list[OutgoingCallDecl]:
1870
1870
  del project_root
1871
- from java_ontology import ( # deferred: java_ontology imports ast_java
1871
+ from java_codebase_rag.graph.java_ontology import ( # deferred: java_ontology imports ast_java
1872
1872
  CLIENT_KIND_FEIGN_METHOD,
1873
1873
  CLIENT_KIND_REST_TEMPLATE,
1874
1874
  CLIENT_KIND_WEB_CLIENT,
java_codebase_rag/cli.py CHANGED
@@ -27,6 +27,7 @@ from java_codebase_rag.config import (
27
27
  from java_codebase_rag._fdlimit import raise_fd_limit
28
28
  from java_codebase_rag._version import version_string
29
29
  from java_codebase_rag.pipeline import (
30
+ VECTORS_SKIPPED_GRAPH_ONLY as _VECTORS_SKIPPED_GRAPH_ONLY,
30
31
  clip,
31
32
  is_cocoindex_preflight_blocker,
32
33
  is_graph_preflight_blocker,
@@ -35,7 +36,7 @@ from java_codebase_rag.pipeline import (
35
36
  run_cocoindex_update,
36
37
  run_incremental_graph,
37
38
  )
38
- from java_ontology import VALID_UNRESOLVED_CALL_REASONS
39
+ from java_codebase_rag.graph.java_ontology import VALID_UNRESOLVED_CALL_REASONS
39
40
 
40
41
  LADYBUG_INCREMENTAL_TRACKING_ISSUE_URL = "https://github.com/HumanBean17/java-codebase-rag/issues/73"
41
42
 
@@ -72,12 +73,6 @@ def _reprocess_drift_graph_only_line(index_dir: Path) -> str:
72
73
  )
73
74
 
74
75
 
75
- _VECTORS_SKIPPED_GRAPH_ONLY = (
76
- "java-codebase-rag: vectors skipped — vector stack not installed on this platform "
77
- "(graph-only mode). The graph is built/refreshed; semantic search is unavailable."
78
- )
79
-
80
-
81
76
  def _reprocess_exit_code(payload: dict[str, Any]) -> int:
82
77
  if payload.get("success"):
83
78
  return 0
@@ -607,7 +602,7 @@ def _cmd_reprocess(args: argparse.Namespace) -> int:
607
602
  _emit_reprocess_outcome(payload, selective_tty_mode="graph" if ok else None)
608
603
  return _reprocess_exit_code(payload)
609
604
 
610
- import server # lazy: pulls sentence_transformers/torch/lancedb/ladybug
605
+ from java_codebase_rag.mcp import server # lazy: pulls sentence_transformers/torch/lancedb/ladybug
611
606
 
612
607
  result = asyncio.run(
613
608
  server.run_refresh_pipeline(
@@ -682,7 +677,7 @@ def _cmd_erase(args: argparse.Namespace) -> int:
682
677
  # tree_sitter (~54ms), and these filenames are only needed on the erase path.
683
678
  # Keeping it out of the top-level import lets `java-codebase-rag --help` (and
684
679
  # every other command) stay fast -- see the lazy-import invariant atop this file.
685
- from build_ast_graph import BUILDER_OWNED_INDEX_FILES
680
+ from java_codebase_rag.graph.build_ast_graph import BUILDER_OWNED_INDEX_FILES
686
681
  builder_paths = [cfg.ladybug_path.parent / name for name in BUILDER_OWNED_INDEX_FILES]
687
682
  operator_paths = [cfg.index_dir / name for name in OPERATOR_OWNED_INDEX_FILES]
688
683
  to_describe: list[Path] = [
@@ -773,12 +768,12 @@ def _cmd_erase(args: argparse.Namespace) -> int:
773
768
 
774
769
 
775
770
  def _cmd_meta(args: argparse.Namespace) -> int:
776
- import server # lazy
771
+ from java_codebase_rag.mcp import server # lazy
777
772
 
778
773
  cfg = _resolved_from_ns(args)
779
774
  _startup_hints(cfg)
780
775
  cfg.apply_to_os_environ()
781
- from ladybug_queries import LadybugGraph # lazy
776
+ from java_codebase_rag.graph.ladybug_queries import LadybugGraph # lazy
782
777
 
783
778
  LadybugGraph._instance = None
784
779
  LadybugGraph._instance_path = None
@@ -797,7 +792,7 @@ def _cmd_meta(args: argparse.Namespace) -> int:
797
792
 
798
793
 
799
794
  def _cmd_tables(args: argparse.Namespace) -> int:
800
- import server # lazy
795
+ from java_codebase_rag.mcp import server # lazy
801
796
 
802
797
  cfg = _resolved_from_ns(args)
803
798
  _startup_hints(cfg)
@@ -808,8 +803,8 @@ def _cmd_tables(args: argparse.Namespace) -> int:
808
803
 
809
804
 
810
805
  def _cmd_diagnose_ignore(args: argparse.Namespace) -> int:
811
- import server # lazy
812
- from path_filtering import LayeredIgnore # lazy
806
+ from java_codebase_rag.mcp import server # lazy
807
+ from java_codebase_rag.graph.path_filtering import LayeredIgnore # lazy
813
808
 
814
809
  cfg = _resolved_from_ns(args)
815
810
  _startup_hints(cfg)
@@ -838,7 +833,7 @@ def _cmd_unresolved_calls_list(args: argparse.Namespace) -> int:
838
833
  cfg = _resolved_from_ns(args)
839
834
  _startup_hints(cfg)
840
835
  cfg.apply_to_os_environ()
841
- from ladybug_queries import LadybugGraph # lazy
836
+ from java_codebase_rag.graph.ladybug_queries import LadybugGraph # lazy
842
837
 
843
838
  if not LadybugGraph.exists():
844
839
  _emit({"success": False, "message": "LadybugDB graph not found"})
@@ -859,7 +854,7 @@ def _cmd_unresolved_calls_stats(args: argparse.Namespace) -> int:
859
854
  cfg = _resolved_from_ns(args)
860
855
  _startup_hints(cfg)
861
856
  cfg.apply_to_os_environ()
862
- from ladybug_queries import LadybugGraph # lazy
857
+ from java_codebase_rag.graph.ladybug_queries import LadybugGraph # lazy
863
858
 
864
859
  if not LadybugGraph.exists():
865
860
  _emit({"success": False, "message": "LadybugDB graph not found"})
@@ -883,8 +878,8 @@ def _cmd_analyze_pr(args: argparse.Namespace) -> int:
883
878
  if not diff_text.strip():
884
879
  _emit({"success": False, "message": "Diff is empty"})
885
880
  return 1
886
- import pr_analysis # lazy
887
- from ladybug_queries import LadybugGraph # lazy
881
+ from java_codebase_rag.analysis import pr_analysis # lazy
882
+ from java_codebase_rag.graph.ladybug_queries import LadybugGraph # lazy
888
883
 
889
884
  if not LadybugGraph.exists():
890
885
  _emit({"success": False, "message": "LadybugDB graph not found"})
@@ -363,6 +363,17 @@ class ResolvedOperatorConfig:
363
363
  embedding_model_source: SettingSource
364
364
  embedding_device_source: SettingSource
365
365
  hints_enabled_source: SettingSource
366
+ # Absence diagnosis config knobs (PR-ABS-0)
367
+ absence_close_threshold: float
368
+ absence_absent_floor: float
369
+ absence_candidate_count: int
370
+ absence_ngram_q: int
371
+ absence_diag_enabled: bool
372
+ absence_close_threshold_source: SettingSource
373
+ absence_absent_floor_source: SettingSource
374
+ absence_candidate_count_source: SettingSource
375
+ absence_ngram_q_source: SettingSource
376
+ absence_diag_enabled_source: SettingSource
366
377
  # Absolute path of the YAML actually loaded (None when built-in defaults were
367
378
  # used with no config file). Recorded into the index dir at index time so a
368
379
  # later discovery run from a sibling/cwd can relocate this config.
@@ -380,6 +391,8 @@ class ResolvedOperatorConfig:
380
391
  os.environ["SBERT_MODEL"] = self.embedding_model
381
392
  if self.embedding_device is not None:
382
393
  os.environ["SBERT_DEVICE"] = self.embedding_device
394
+ # Publish absence diagnosis knobs for subprocess builds (PR-ABS-1)
395
+ os.environ["JAVA_CODEBASE_RAG_ABSENCE_NGRAM_Q"] = str(self.absence_ngram_q)
383
396
 
384
397
  def subprocess_env(self, base: dict[str, str] | None = None) -> dict[str, str]:
385
398
  out = dict(base or os.environ)
@@ -390,6 +403,8 @@ class ResolvedOperatorConfig:
390
403
  out["SBERT_DEVICE"] = self.embedding_device
391
404
  else:
392
405
  out.pop("SBERT_DEVICE", None)
406
+ # Publish absence diagnosis knobs for subprocess builds (PR-ABS-1)
407
+ out["JAVA_CODEBASE_RAG_ABSENCE_NGRAM_Q"] = str(self.absence_ngram_q)
393
408
  return out
394
409
 
395
410
 
@@ -459,6 +474,66 @@ def _pick_bool(
459
474
  return default, "default"
460
475
 
461
476
 
477
+ def _pick_float(
478
+ *,
479
+ env_key: str,
480
+ yaml_dict: dict[str, Any],
481
+ yaml_path: tuple[str, ...],
482
+ default: float,
483
+ ) -> tuple[float, SettingSource]:
484
+ """Pick a float setting from env (parsed via float(...)), YAML, or default.
485
+
486
+ Precedence: CLI > env > YAML > default. Env values that fail to parse as float
487
+ fall back to the default (matching the brief's requirement for graceful degradation).
488
+ """
489
+ env_raw = os.environ.get(env_key, "").strip()
490
+ if env_raw:
491
+ try:
492
+ return float(env_raw), "env"
493
+ except ValueError:
494
+ # Invalid env value falls back to default (per brief)
495
+ pass
496
+ cur: Any = yaml_dict
497
+ for part in yaml_path:
498
+ if not isinstance(cur, dict) or part not in cur:
499
+ cur = None
500
+ break
501
+ cur = cur.get(part)
502
+ if isinstance(cur, (int, float)):
503
+ return float(cur), "yaml"
504
+ return default, "default"
505
+
506
+
507
+ def _pick_int(
508
+ *,
509
+ env_key: str,
510
+ yaml_dict: dict[str, Any],
511
+ yaml_path: tuple[str, ...],
512
+ default: int,
513
+ ) -> tuple[int, SettingSource]:
514
+ """Pick an int setting from env (parsed via int(...)), YAML, or default.
515
+
516
+ Precedence: CLI > env > YAML > default. Env values that fail to parse as int
517
+ fall back to the default (matching the brief's requirement for graceful degradation).
518
+ """
519
+ env_raw = os.environ.get(env_key, "").strip()
520
+ if env_raw:
521
+ try:
522
+ return int(env_raw), "env"
523
+ except ValueError:
524
+ # Invalid env value falls back to default (per brief)
525
+ pass
526
+ cur: Any = yaml_dict
527
+ for part in yaml_path:
528
+ if not isinstance(cur, dict) or part not in cur:
529
+ cur = None
530
+ break
531
+ cur = cur.get(part)
532
+ if isinstance(cur, int):
533
+ return cur, "yaml"
534
+ return default, "default"
535
+
536
+
462
537
  def _resolve_index_dir_path(
463
538
  *,
464
539
  source_root: Path,
@@ -565,6 +640,37 @@ def resolve_operator_config(
565
640
  yaml_path=("hints", "enabled"),
566
641
  default=True,
567
642
  )
643
+ # Absence diagnosis config (PR-ABS-0)
644
+ abs_close, abs_close_src = _pick_float(
645
+ env_key="JAVA_CODEBASE_RAG_ABSENCE_CLOSE_THRESHOLD",
646
+ yaml_dict=yaml_dict,
647
+ yaml_path=("absence", "close_threshold"),
648
+ default=0.85,
649
+ )
650
+ abs_floor, abs_floor_src = _pick_float(
651
+ env_key="JAVA_CODEBASE_RAG_ABSENCE_ABSENT_FLOOR",
652
+ yaml_dict=yaml_dict,
653
+ yaml_path=("absence", "absent_floor"),
654
+ default=0.40,
655
+ )
656
+ abs_cand, abs_cand_src = _pick_int(
657
+ env_key="JAVA_CODEBASE_RAG_ABSENCE_CANDIDATE_COUNT",
658
+ yaml_dict=yaml_dict,
659
+ yaml_path=("absence", "candidate_count"),
660
+ default=5,
661
+ )
662
+ abs_q, abs_q_src = _pick_int(
663
+ env_key="JAVA_CODEBASE_RAG_ABSENCE_NGRAM_Q",
664
+ yaml_dict=yaml_dict,
665
+ yaml_path=("absence", "ngram_q"),
666
+ default=3,
667
+ )
668
+ abs_diag, abs_diag_src = _pick_bool(
669
+ env_key="JAVA_CODEBASE_RAG_ABSENCE_DIAG_ENABLED",
670
+ yaml_dict=yaml_dict,
671
+ yaml_path=("absence", "diag_enabled"),
672
+ default=True,
673
+ )
568
674
  ku = index_dir / "code_graph.lbug"
569
675
  coco = index_dir / "cocoindex.db"
570
676
  return ResolvedOperatorConfig(
@@ -579,6 +685,16 @@ def resolve_operator_config(
579
685
  embedding_model_source=model_src,
580
686
  embedding_device_source=device_src,
581
687
  hints_enabled_source=hints_src,
688
+ absence_close_threshold=abs_close,
689
+ absence_absent_floor=abs_floor,
690
+ absence_candidate_count=abs_cand,
691
+ absence_ngram_q=abs_q,
692
+ absence_diag_enabled=abs_diag,
693
+ absence_close_threshold_source=abs_close_src,
694
+ absence_absent_floor_source=abs_floor_src,
695
+ absence_candidate_count_source=abs_cand_src,
696
+ absence_ngram_q_source=abs_q_src,
697
+ absence_diag_enabled_source=abs_diag_src,
582
698
  yaml_config_path=find_yaml_config_file(config_dir),
583
699
  )
584
700
 
File without changes