generated from coulomb/repo-seed
Coevolution extension
This commit is contained in:
@@ -69,6 +69,23 @@ MANIFEST_FRAMEWORK_HINTS = {
|
||||
},
|
||||
}
|
||||
|
||||
LLM_PROVIDER_HINTS = {
|
||||
"openrouter": "OpenRouter",
|
||||
"anthropic": "Anthropic",
|
||||
"claude": "Claude",
|
||||
"openai": "OpenAI",
|
||||
"gemini": "Gemini",
|
||||
"google-generativeai": "Gemini",
|
||||
}
|
||||
|
||||
LLM_CREDENTIAL_HINTS = {
|
||||
"OPENROUTER_API_KEY": "OpenRouter API key",
|
||||
"ANTHROPIC_API_KEY": "Anthropic API key",
|
||||
"OPENAI_API_KEY": "OpenAI API key",
|
||||
"GEMINI_API_KEY": "Gemini API key",
|
||||
"GOOGLE_API_KEY": "Google API key",
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FactCandidate:
|
||||
@@ -102,6 +119,7 @@ class DeterministicScanner:
|
||||
facts.extend(self._classified_file_facts(files, root))
|
||||
facts.extend(self._framework_facts(files, root))
|
||||
facts.extend(self._interface_facts(files, root))
|
||||
facts.extend(self._llm_provider_facts(files, root))
|
||||
|
||||
return ScanResult(
|
||||
source_path=str(root),
|
||||
@@ -223,6 +241,96 @@ class DeterministicScanner:
|
||||
facts.append(FactCandidate("interface", "possible API surface", relative))
|
||||
return facts
|
||||
|
||||
def _llm_provider_facts(self, files: list[Path], root: Path) -> list[FactCandidate]:
|
||||
facts: list[FactCandidate] = []
|
||||
seen: set[tuple[str, str, str]] = set()
|
||||
for path in files:
|
||||
if path.suffix.lower() not in {
|
||||
".py",
|
||||
".ts",
|
||||
".js",
|
||||
".json",
|
||||
".toml",
|
||||
".yaml",
|
||||
".yml",
|
||||
".md",
|
||||
".txt",
|
||||
".env",
|
||||
} and not path.name.lower().startswith(".env"):
|
||||
continue
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")
|
||||
except OSError:
|
||||
continue
|
||||
lower_text = text.lower()
|
||||
relative = path.relative_to(root).as_posix()
|
||||
for needle, provider in LLM_PROVIDER_HINTS.items():
|
||||
if needle not in lower_text:
|
||||
continue
|
||||
self._append_once(
|
||||
facts,
|
||||
seen,
|
||||
FactCandidate(
|
||||
kind="llm_provider",
|
||||
name=provider,
|
||||
path=relative,
|
||||
value=needle,
|
||||
metadata={"source": "provider_hint"},
|
||||
),
|
||||
)
|
||||
for env_name, label in LLM_CREDENTIAL_HINTS.items():
|
||||
if env_name.lower() not in lower_text:
|
||||
continue
|
||||
self._append_once(
|
||||
facts,
|
||||
seen,
|
||||
FactCandidate(
|
||||
kind="credential_config",
|
||||
name=label,
|
||||
path=relative,
|
||||
value=env_name,
|
||||
metadata={"source": "environment_variable"},
|
||||
),
|
||||
)
|
||||
if any(term in lower_text for term in ("provider_registry", "providers =", "adapter")):
|
||||
if any(needle in lower_text for needle in LLM_PROVIDER_HINTS):
|
||||
self._append_once(
|
||||
facts,
|
||||
seen,
|
||||
FactCandidate(
|
||||
kind="provider_registry",
|
||||
name="LLM provider registry",
|
||||
path=relative,
|
||||
metadata={"source": "provider_registry_hint"},
|
||||
),
|
||||
)
|
||||
if "fallback" in lower_text and any(
|
||||
needle in lower_text for needle in LLM_PROVIDER_HINTS
|
||||
):
|
||||
self._append_once(
|
||||
facts,
|
||||
seen,
|
||||
FactCandidate(
|
||||
kind="fallback_policy",
|
||||
name="LLM provider fallback policy",
|
||||
path=relative,
|
||||
metadata={"source": "fallback_hint"},
|
||||
),
|
||||
)
|
||||
return facts
|
||||
|
||||
def _append_once(
|
||||
self,
|
||||
facts: list[FactCandidate],
|
||||
seen: set[tuple[str, str, str]],
|
||||
fact: FactCandidate,
|
||||
) -> None:
|
||||
key = (fact.kind, fact.name, fact.path)
|
||||
if key in seen:
|
||||
return
|
||||
seen.add(key)
|
||||
facts.append(fact)
|
||||
|
||||
def _python_interface_facts(self, path: Path, relative: str) -> list[FactCandidate]:
|
||||
facts: list[FactCandidate] = []
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user