feat: Add templates for autonomous actions, orchestrators, sequential phases, and skill documentation

- Introduced a comprehensive template for autonomous actions, detailing structure, execution, and error handling.
- Added an orchestrator template to manage state and decision logic for autonomous actions.
- Created a sequential phase template to outline execution steps and objectives for structured workflows.
- Developed a skill documentation template to standardize the generation of skill entry files.
- Implemented a Python script to compare search results between hybrid and cascade methods, analyzing ranking changes.
This commit is contained in:
catlog22
2026-01-03 15:58:31 +08:00
parent ac23fe5b5a
commit 9922d455da
17 changed files with 4625 additions and 14 deletions

View File

@@ -439,6 +439,11 @@ def search(
"--weights", "-w",
help="RRF weights as key=value pairs (e.g., 'splade=0.4,vector=0.6' or 'fts=0.4,vector=0.6'). Default: auto-detect based on available backends."
),
cascade_strategy: Optional[str] = typer.Option(
None,
"--cascade-strategy",
help="Cascade search strategy: 'binary' (fast binary+dense) or 'hybrid' (FTS+cross-encoder). Only used with --method cascade."
),
# Hidden deprecated parameter for backward compatibility
mode: Optional[str] = typer.Option(None, "--mode", hidden=True, help="[DEPRECATED] Use --method instead."),
json_mode: bool = typer.Option(False, "--json", help="Output JSON response."),
@@ -488,9 +493,12 @@ def search(
# SPLADE sparse neural search
codexlens search "user login flow" --method splade
# Fast cascade retrieval for large codebases
# Fast cascade retrieval for large codebases (binary strategy)
codexlens search "authentication" --method cascade
# Cascade with cross-encoder reranking (hybrid strategy)
codexlens search "authentication" --method cascade --cascade-strategy hybrid
# Hybrid with custom weights
codexlens search "authentication" --method hybrid --weights splade=0.5,vector=0.5
"""
@@ -540,6 +548,20 @@ def search(
console.print(f"[dim]Valid methods: {', '.join(valid_methods)}[/dim]")
raise typer.Exit(code=1)
# Validate cascade_strategy if provided
if cascade_strategy is not None:
valid_strategies = ["binary", "hybrid"]
if cascade_strategy not in valid_strategies:
if json_mode:
print_json(success=False, error=f"Invalid cascade strategy: {cascade_strategy}. Must be one of: {', '.join(valid_strategies)}")
else:
console.print(f"[red]Invalid cascade strategy:[/red] {cascade_strategy}")
console.print(f"[dim]Valid strategies: {', '.join(valid_strategies)}[/dim]")
raise typer.Exit(code=1)
# Warn if using cascade_strategy with non-cascade method
if actual_method != "cascade" and not json_mode:
console.print(f"[yellow]Warning: --cascade-strategy is only effective with --method cascade[/yellow]")
# Parse custom weights if provided
hybrid_weights = None
if weights:
@@ -671,7 +693,7 @@ def search(
else:
# Dispatch to cascade_search for cascade method
if actual_method == "cascade":
result = engine.cascade_search(query, search_path, k=limit, options=options)
result = engine.cascade_search(query, search_path, k=limit, options=options, strategy=cascade_strategy)
else:
result = engine.search(query, search_path, options)
results_list = [

View File

@@ -271,6 +271,11 @@ class Config:
"model": self.reranker_model,
"top_k": self.reranker_top_k,
},
"cascade": {
"strategy": self.cascade_strategy,
"coarse_k": self.cascade_coarse_k,
"fine_k": self.cascade_fine_k,
},
}
with open(self.settings_path, "w", encoding="utf-8") as f:
json.dump(settings, f, indent=2)
@@ -338,6 +343,23 @@ class Config:
self.reranker_model = reranker["model"]
if "top_k" in reranker:
self.reranker_top_k = reranker["top_k"]
# Load cascade settings
cascade = settings.get("cascade", {})
if "strategy" in cascade:
strategy = cascade["strategy"]
if strategy in {"binary", "hybrid"}:
self.cascade_strategy = strategy
else:
log.warning(
"Invalid cascade strategy in %s: %r (expected 'binary' or 'hybrid')",
self.settings_path,
strategy,
)
if "coarse_k" in cascade:
self.cascade_coarse_k = cascade["coarse_k"]
if "fine_k" in cascade:
self.cascade_fine_k = cascade["fine_k"]
except Exception as exc:
log.warning(
"Failed to load settings from %s (%s): %s",

View File

@@ -797,7 +797,7 @@ class ChainSearchEngine:
k: int = 10,
coarse_k: int = 100,
options: Optional[SearchOptions] = None,
strategy: Literal["binary", "hybrid"] = "binary",
strategy: Optional[Literal["binary", "hybrid"]] = None,
) -> ChainSearchResult:
"""Unified cascade search entry point with strategy selection.
@@ -805,9 +805,9 @@ class ChainSearchEngine:
- "binary": Uses binary vector coarse ranking + dense fine ranking (faster)
- "hybrid": Uses FTS+SPLADE+Vector coarse ranking + cross-encoder reranking (original)
The strategy can be configured via:
1. The `strategy` parameter (highest priority)
2. Config `cascade_strategy` setting
The strategy is determined with the following priority:
1. The `strategy` parameter (e.g., from CLI --cascade-strategy option)
2. Config `cascade_strategy` setting from settings.json
3. Default: "binary"
Args:
@@ -816,7 +816,7 @@ class ChainSearchEngine:
k: Number of final results to return (default 10)
coarse_k: Number of coarse candidates from first stage (default 100)
options: Search configuration (uses defaults if None)
strategy: Cascade strategy - "binary" or "hybrid" (default "binary")
strategy: Cascade strategy - "binary" or "hybrid". Overrides config if provided.
Returns:
ChainSearchResult with reranked results and statistics
@@ -828,14 +828,18 @@ class ChainSearchEngine:
>>> # Use hybrid cascade (original behavior)
>>> result = engine.cascade_search("auth", Path("D:/project"), strategy="hybrid")
"""
# Check config for strategy override
# Strategy priority: parameter > config > default
effective_strategy = strategy
if self._config is not None:
config_strategy = getattr(self._config, "cascade_strategy", None)
if config_strategy in ("binary", "hybrid"):
# Only use config if no explicit strategy was passed
# (we can't detect if strategy was explicitly passed vs default)
effective_strategy = config_strategy
if effective_strategy is None:
# Not passed via parameter, check config
if self._config is not None:
config_strategy = getattr(self._config, "cascade_strategy", None)
if config_strategy in ("binary", "hybrid"):
effective_strategy = config_strategy
# If still not set, apply default
if effective_strategy not in ("binary", "hybrid"):
effective_strategy = "binary"
if effective_strategy == "binary":
return self.binary_cascade_search(query, source_path, k, coarse_k, options)