attocode-code-intel 0.1.0__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.
- attocode_code_intel-0.1.0.dist-info/METADATA +221 -0
- attocode_code_intel-0.1.0.dist-info/RECORD +345 -0
- attocode_code_intel-0.1.0.dist-info/WHEEL +4 -0
- attocode_code_intel-0.1.0.dist-info/entry_points.txt +2 -0
- attocode_code_intel-0.1.0.dist-info/licenses/LICENSE +21 -0
- attocode_intel/GUIDELINES.md +432 -0
- attocode_intel/__init__.py +52 -0
- attocode_intel/_internal/__init__.py +1 -0
- attocode_intel/_internal/errors/__init__.py +126 -0
- attocode_intel/_internal/integrations/__init__.py +1 -0
- attocode_intel/_internal/integrations/context/__init__.py +1 -0
- attocode_intel/_internal/integrations/context/architecture_drift.py +354 -0
- attocode_intel/_internal/integrations/context/ast_chunker.py +202 -0
- attocode_intel/_internal/integrations/context/ast_service.py +1483 -0
- attocode_intel/_internal/integrations/context/blob_oid.py +423 -0
- attocode_intel/_internal/integrations/context/cache_manifest.py +221 -0
- attocode_intel/_internal/integrations/context/cas.py +466 -0
- attocode_intel/_internal/integrations/context/code_analyzer.py +528 -0
- attocode_intel/_internal/integrations/context/codebase_ast.py +1461 -0
- attocode_intel/_internal/integrations/context/codebase_context.py +1736 -0
- attocode_intel/_internal/integrations/context/cross_mode.py +263 -0
- attocode_intel/_internal/integrations/context/cross_references.py +616 -0
- attocode_intel/_internal/integrations/context/embedding_rotation.py +597 -0
- attocode_intel/_internal/integrations/context/embeddings.py +282 -0
- attocode_intel/_internal/integrations/context/frecency.py +427 -0
- attocode_intel/_internal/integrations/context/fuzzy.py +320 -0
- attocode_intel/_internal/integrations/context/hierarchical_explorer.py +331 -0
- attocode_intel/_internal/integrations/context/hydration.py +90 -0
- attocode_intel/_internal/integrations/context/index_repair.py +87 -0
- attocode_intel/_internal/integrations/context/index_store.py +586 -0
- attocode_intel/_internal/integrations/context/memory_store.py +602 -0
- attocode_intel/_internal/integrations/context/module_resolution.py +52 -0
- attocode_intel/_internal/integrations/context/query_constraints.py +361 -0
- attocode_intel/_internal/integrations/context/query_history.py +417 -0
- attocode_intel/_internal/integrations/context/reranker.py +351 -0
- attocode_intel/_internal/integrations/context/semantic_search.py +2931 -0
- attocode_intel/_internal/integrations/context/syntax_evidence.py +94 -0
- attocode_intel/_internal/integrations/context/systemone_ranker.py +245 -0
- attocode_intel/_internal/integrations/context/temporal_coupling.py +411 -0
- attocode_intel/_internal/integrations/context/trigram_index.py +820 -0
- attocode_intel/_internal/integrations/context/trigram_regex.py +171 -0
- attocode_intel/_internal/integrations/context/ts_parser.py +2199 -0
- attocode_intel/_internal/integrations/context/vector_store.py +795 -0
- attocode_intel/_internal/integrations/feature_flags/__init__.py +357 -0
- attocode_intel/_internal/integrations/lsp/__init__.py +1 -0
- attocode_intel/_internal/integrations/lsp/client.py +1140 -0
- attocode_intel/_internal/integrations/mcp/__init__.py +1 -0
- attocode_intel/_internal/integrations/mcp/client.py +253 -0
- attocode_intel/_internal/integrations/security/__init__.py +1 -0
- attocode_intel/_internal/integrations/security/custom_rules.py +176 -0
- attocode_intel/_internal/integrations/security/dataflow.py +522 -0
- attocode_intel/_internal/integrations/security/dependency_audit.py +303 -0
- attocode_intel/_internal/integrations/security/matcher.py +44 -0
- attocode_intel/_internal/integrations/security/patterns.py +724 -0
- attocode_intel/_internal/integrations/security/scanner.py +351 -0
- attocode_intel/_internal/integrations/utilities/__init__.py +1 -0
- attocode_intel/_internal/integrations/utilities/ignore.py +64 -0
- attocode_intel/_internal/integrations/utilities/token_estimate.py +51 -0
- attocode_intel/_internal/tricks/__init__.py +1 -0
- attocode_intel/_internal/tricks/recursive_context.py +357 -0
- attocode_intel/_internal/types/__init__.py +1 -0
- attocode_intel/_internal/types/events.py +289 -0
- attocode_intel/_internal/types/severity.py +15 -0
- attocode_intel/_shared.py +341 -0
- attocode_intel/analysis_coverage.py +56 -0
- attocode_intel/api/__init__.py +1 -0
- attocode_intel/api/access.py +32 -0
- attocode_intel/api/app.py +247 -0
- attocode_intel/api/auth/__init__.py +128 -0
- attocode_intel/api/auth/api_keys.py +61 -0
- attocode_intel/api/auth/context.py +34 -0
- attocode_intel/api/auth/jwt.py +66 -0
- attocode_intel/api/auth/oauth.py +146 -0
- attocode_intel/api/auth/passwords.py +15 -0
- attocode_intel/api/deps.py +351 -0
- attocode_intel/api/knowledge_bridge.py +13 -0
- attocode_intel/api/mcp_transport.py +51 -0
- attocode_intel/api/middleware.py +411 -0
- attocode_intel/api/models.py +698 -0
- attocode_intel/api/providers/__init__.py +1 -0
- attocode_intel/api/providers/db_provider.py +1106 -0
- attocode_intel/api/providers/local_provider.py +476 -0
- attocode_intel/api/providers/remote_provider.py +740 -0
- attocode_intel/api/repository_source.py +21 -0
- attocode_intel/api/routes/__init__.py +1 -0
- attocode_intel/api/routes/_pin_helper.py +158 -0
- attocode_intel/api/routes/activity.py +148 -0
- attocode_intel/api/routes/adr.py +102 -0
- attocode_intel/api/routes/analysis.py +515 -0
- attocode_intel/api/routes/api_keys.py +170 -0
- attocode_intel/api/routes/auth.py +428 -0
- attocode_intel/api/routes/branches.py +262 -0
- attocode_intel/api/routes/cross_repo_search.py +198 -0
- attocode_intel/api/routes/embeddings.py +386 -0
- attocode_intel/api/routes/files.py +132 -0
- attocode_intel/api/routes/files_v2.py +388 -0
- attocode_intel/api/routes/gc.py +322 -0
- attocode_intel/api/routes/git_v2.py +433 -0
- attocode_intel/api/routes/graph.py +174 -0
- attocode_intel/api/routes/graph_viz.py +160 -0
- attocode_intel/api/routes/health.py +62 -0
- attocode_intel/api/routes/history.py +175 -0
- attocode_intel/api/routes/jobs.py +84 -0
- attocode_intel/api/routes/learning.py +205 -0
- attocode_intel/api/routes/lsp.py +272 -0
- attocode_intel/api/routes/notify.py +623 -0
- attocode_intel/api/routes/operations.py +27 -0
- attocode_intel/api/routes/orgs.py +924 -0
- attocode_intel/api/routes/preferences.py +100 -0
- attocode_intel/api/routes/presence.py +42 -0
- attocode_intel/api/routes/projects.py +116 -0
- attocode_intel/api/routes/repos.py +47 -0
- attocode_intel/api/routes/search.py +180 -0
- attocode_intel/api/routes/snapshots.py +614 -0
- attocode_intel/api/routes/webhooks.py +313 -0
- attocode_intel/api/routes/websocket.py +116 -0
- attocode_intel/api/static/graph.html +239 -0
- attocode_intel/api/utils.py +96 -0
- attocode_intel/artifacts/__init__.py +45 -0
- attocode_intel/artifacts/hashing.py +230 -0
- attocode_intel/artifacts/provenance.py +190 -0
- attocode_intel/artifacts/retrieval_pin.py +159 -0
- attocode_intel/audit.py +59 -0
- attocode_intel/bug_finder.py +206 -0
- attocode_intel/bundle.py +80 -0
- attocode_intel/catalog.py +242 -0
- attocode_intel/change_review.py +75 -0
- attocode_intel/cli.py +3062 -0
- attocode_intel/community.py +63 -0
- attocode_intel/confidence/__init__.py +144 -0
- attocode_intel/confidence/jev.py +234 -0
- attocode_intel/confidence/llm.py +330 -0
- attocode_intel/confidence/redact.py +44 -0
- attocode_intel/confidence/settings.py +74 -0
- attocode_intel/config.py +256 -0
- attocode_intel/crypto.py +31 -0
- attocode_intel/db/__init__.py +7 -0
- attocode_intel/db/base.py +33 -0
- attocode_intel/db/engine.py +61 -0
- attocode_intel/db/models.py +529 -0
- attocode_intel/entrypoint.py +185 -0
- attocode_intel/focused_evidence.py +130 -0
- attocode_intel/freshness.py +154 -0
- attocode_intel/gateway.py +734 -0
- attocode_intel/git/__init__.py +7 -0
- attocode_intel/git/credentials.py +75 -0
- attocode_intel/git/manager.py +493 -0
- attocode_intel/git/models.py +96 -0
- attocode_intel/git/storage.py +98 -0
- attocode_intel/graph_query_parser.py +761 -0
- attocode_intel/helpers.py +712 -0
- attocode_intel/indexing/__init__.py +29 -0
- attocode_intel/indexing/debouncer.py +136 -0
- attocode_intel/indexing/delta_indexer.py +151 -0
- attocode_intel/indexing/full_indexer.py +323 -0
- attocode_intel/indexing/incremental.py +240 -0
- attocode_intel/indexing/parser.py +403 -0
- attocode_intel/indexing/summarizer.py +264 -0
- attocode_intel/installer.py +1896 -0
- attocode_intel/knowledge.py +269 -0
- attocode_intel/local_knowledge.py +77 -0
- attocode_intel/migrations/alembic.ini +36 -0
- attocode_intel/migrations/env.py +71 -0
- attocode_intel/migrations/script.py.mako +27 -0
- attocode_intel/migrations/versions/001_initial_schema.py +219 -0
- attocode_intel/migrations/versions/002_branch_version_and_embeddings.py +61 -0
- attocode_intel/migrations/versions/003_embedding_uniqueness_and_cascade.py +51 -0
- attocode_intel/migrations/versions/004_audit_events.py +38 -0
- attocode_intel/migrations/versions/005_user_preferences.py +30 -0
- attocode_intel/migrations/versions/006_google_oauth.py +27 -0
- attocode_intel/migrations/versions/007_pgvector_embeddings.py +28 -0
- attocode_intel/migrations/versions/008_symbol_references.py +37 -0
- attocode_intel/migrations/versions/009_webhook_secret_encryption.py +25 -0
- attocode_intel/migrations/versions/010_add_commits_table.py +40 -0
- attocode_intel/migrations/versions/011_commit_changed_files.py +25 -0
- attocode_intel/migrations/versions/012_branch_merged_at.py +25 -0
- attocode_intel/migrations/versions/013_revoked_tokens.py +32 -0
- attocode_intel/migrations/versions/014_blame_hunks.py +40 -0
- attocode_intel/migrations/versions/015_commit_file_stats.py +40 -0
- attocode_intel/migrations/versions/016_embedding_provenance_columns.py +179 -0
- attocode_intel/migrations/versions/017_provenance_table.py +102 -0
- attocode_intel/migrations/versions/018_repo_snapshots.py +178 -0
- attocode_intel/migrations/versions/019_symref_caller.py +42 -0
- attocode_intel/migrations/versions/020_shared_knowledge.py +29 -0
- attocode_intel/onboarding.py +258 -0
- attocode_intel/output.py +178 -0
- attocode_intel/precision.py +133 -0
- attocode_intel/presence.py +160 -0
- attocode_intel/probe.py +110 -0
- attocode_intel/project_dir.py +97 -0
- attocode_intel/pubsub.py +113 -0
- attocode_intel/query_ranking.py +242 -0
- attocode_intel/readiness.py +972 -0
- attocode_intel/redis.py +51 -0
- attocode_intel/reference_pages.py +60 -0
- attocode_intel/remote.py +131 -0
- attocode_intel/repo_ranker.py +246 -0
- attocode_intel/request_context.py +82 -0
- attocode_intel/rules/__init__.py +28 -0
- attocode_intel/rules/ci.py +320 -0
- attocode_intel/rules/combinators.py +293 -0
- attocode_intel/rules/enricher.py +127 -0
- attocode_intel/rules/evolution.py +452 -0
- attocode_intel/rules/executor.py +531 -0
- attocode_intel/rules/filters/__init__.py +5 -0
- attocode_intel/rules/filters/pipeline.py +151 -0
- attocode_intel/rules/formatter.py +198 -0
- attocode_intel/rules/hygiene.py +242 -0
- attocode_intel/rules/importers/__init__.py +1 -0
- attocode_intel/rules/importers/semgrep.py +382 -0
- attocode_intel/rules/loader.py +292 -0
- attocode_intel/rules/marketplace.py +375 -0
- attocode_intel/rules/metavar.py +181 -0
- attocode_intel/rules/model.py +317 -0
- attocode_intel/rules/packs/__init__.py +1 -0
- attocode_intel/rules/packs/community/_license_templates/Apache-2.0.txt +176 -0
- attocode_intel/rules/packs/community/_license_templates/MIT.txt +21 -0
- attocode_intel/rules/packs/community/bandit-python/LICENSE +176 -0
- attocode_intel/rules/packs/community/bandit-python/NOTICE +13 -0
- attocode_intel/rules/packs/community/bandit-python/PORTING.md +23 -0
- attocode_intel/rules/packs/community/bandit-python/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B105-hardcoded-password.yaml +23 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B303-weak-md5.yaml +21 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B304-weak-des.yaml +20 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B307-use-of-eval.yaml +22 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B324-weak-sha1.yaml +21 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B501-no-cert-validation.yaml +23 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B602-shell-true.yaml +22 -0
- attocode_intel/rules/packs/community/bandit-python/rules/B608-sqli.yaml +22 -0
- attocode_intel/rules/packs/community/eslint-typescript/LICENSE +21 -0
- attocode_intel/rules/packs/community/eslint-typescript/NOTICE +13 -0
- attocode_intel/rules/packs/community/eslint-typescript/PORTING.md +23 -0
- attocode_intel/rules/packs/community/eslint-typescript/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/eqeqeq.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-eval.yaml +22 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-implied-eval.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-new-func.yaml +21 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-throw-literal.yaml +19 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-var.yaml +20 -0
- attocode_intel/rules/packs/community/eslint-typescript/rules/no-with.yaml +18 -0
- attocode_intel/rules/packs/community/gosec-go/LICENSE +176 -0
- attocode_intel/rules/packs/community/gosec-go/NOTICE +13 -0
- attocode_intel/rules/packs/community/gosec-go/PORTING.md +23 -0
- attocode_intel/rules/packs/community/gosec-go/manifest.yaml +14 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G101-hardcoded-credentials.yaml +22 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G102-bind-all-interfaces.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G103-unsafe-block.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G201-sql-format.yaml +21 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G304-file-inclusion.yaml +23 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G401-weak-cipher.yaml +20 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G402-tls-min-version.yaml +20 -0
- attocode_intel/rules/packs/community/gosec-go/rules/G501-md5-import.yaml +21 -0
- attocode_intel/rules/packs/examples/cpp/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/cpp/rules/security.yaml +90 -0
- attocode_intel/rules/packs/examples/cpp/rules/structural.yaml +42 -0
- attocode_intel/rules/packs/examples/csharp/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/csharp/rules/security.yaml +69 -0
- attocode_intel/rules/packs/examples/csharp/rules/structural.yaml +42 -0
- attocode_intel/rules/packs/examples/go/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/go/rules/performance.yaml +136 -0
- attocode_intel/rules/packs/examples/go/rules/security.yaml +48 -0
- attocode_intel/rules/packs/examples/go/rules/structural.yaml +58 -0
- attocode_intel/rules/packs/examples/go/taint/sanitizers.yaml +24 -0
- attocode_intel/rules/packs/examples/go/taint/sinks.yaml +51 -0
- attocode_intel/rules/packs/examples/go/taint/sources.yaml +26 -0
- attocode_intel/rules/packs/examples/java/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/java/rules/correctness.yaml +55 -0
- attocode_intel/rules/packs/examples/java/rules/structural.yaml +48 -0
- attocode_intel/rules/packs/examples/java/taint/sinks.yaml +37 -0
- attocode_intel/rules/packs/examples/java/taint/sources.yaml +21 -0
- attocode_intel/rules/packs/examples/kotlin/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/kotlin/rules/correctness.yaml +50 -0
- attocode_intel/rules/packs/examples/kotlin/rules/structural.yaml +38 -0
- attocode_intel/rules/packs/examples/php/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/php/rules/security.yaml +66 -0
- attocode_intel/rules/packs/examples/php/rules/structural.yaml +41 -0
- attocode_intel/rules/packs/examples/python/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/python/rules/performance.yaml +90 -0
- attocode_intel/rules/packs/examples/python/rules/structural.yaml +55 -0
- attocode_intel/rules/packs/examples/ruby/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/ruby/rules/security.yaml +73 -0
- attocode_intel/rules/packs/examples/ruby/rules/structural.yaml +41 -0
- attocode_intel/rules/packs/examples/rust/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/rust/rules/correctness.yaml +51 -0
- attocode_intel/rules/packs/examples/rust/rules/structural.yaml +49 -0
- attocode_intel/rules/packs/examples/typescript/manifest.yaml +4 -0
- attocode_intel/rules/packs/examples/typescript/rules/performance.yaml +70 -0
- attocode_intel/rules/packs/examples/typescript/rules/structural.yaml +48 -0
- attocode_intel/rules/packs/pack_loader.py +244 -0
- attocode_intel/rules/plugins/__init__.py +1 -0
- attocode_intel/rules/plugins/plugin_loader.py +132 -0
- attocode_intel/rules/profiling.py +332 -0
- attocode_intel/rules/registry.py +213 -0
- attocode_intel/rules/sarif.py +187 -0
- attocode_intel/rules/synthesis.py +420 -0
- attocode_intel/rules/testing.py +326 -0
- attocode_intel/server.py +734 -0
- attocode_intel/service.py +3416 -0
- attocode_intel/sharing.py +57 -0
- attocode_intel/storage/__init__.py +6 -0
- attocode_intel/storage/branch_overlay.py +352 -0
- attocode_intel/storage/content_store.py +220 -0
- attocode_intel/storage/dependency_store.py +143 -0
- attocode_intel/storage/diff_engine.py +187 -0
- attocode_intel/storage/embedding_store.py +594 -0
- attocode_intel/storage/provenance_store.py +137 -0
- attocode_intel/storage/security_scanner_db.py +164 -0
- attocode_intel/storage/symbol_store.py +160 -0
- attocode_intel/structural_evidence.py +144 -0
- attocode_intel/symbol_inspection.py +141 -0
- attocode_intel/symbol_links.py +167 -0
- attocode_intel/telemetry.py +42 -0
- attocode_intel/test_ranking.py +73 -0
- attocode_intel/testing/__init__.py +43 -0
- attocode_intel/testing/fixtures.py +122 -0
- attocode_intel/testing/helpers.py +75 -0
- attocode_intel/testing/mocks.py +99 -0
- attocode_intel/tools/__init__.py +2 -0
- attocode_intel/tools/adr_tools.py +628 -0
- attocode_intel/tools/analysis_tools.py +382 -0
- attocode_intel/tools/composite_tools.py +695 -0
- attocode_intel/tools/cross_mode_tools.py +173 -0
- attocode_intel/tools/dead_code_tools.py +582 -0
- attocode_intel/tools/distill_tools.py +353 -0
- attocode_intel/tools/frecency_tools.py +220 -0
- attocode_intel/tools/fuzzy_tools.py +255 -0
- attocode_intel/tools/history_tools.py +486 -0
- attocode_intel/tools/learning_tools.py +222 -0
- attocode_intel/tools/lsp_tools.py +218 -0
- attocode_intel/tools/maintenance_tools.py +1662 -0
- attocode_intel/tools/navigation_tools.py +220 -0
- attocode_intel/tools/overlay_tools.py +540 -0
- attocode_intel/tools/pin_store.py +432 -0
- attocode_intel/tools/pin_tools.py +266 -0
- attocode_intel/tools/query_constraints_tools.py +262 -0
- attocode_intel/tools/query_history_tools.py +158 -0
- attocode_intel/tools/readiness_tools.py +44 -0
- attocode_intel/tools/rule_tools.py +992 -0
- attocode_intel/tools/search_tools.py +770 -0
- attocode_intel/tools/snapshot_tools.py +624 -0
- attocode_intel/workers/__init__.py +1 -0
- attocode_intel/workers/job_utils.py +111 -0
- attocode_intel/workers/jobs.py +573 -0
- attocode_intel/workers/run.py +30 -0
- attocode_intel/workers/settings.py +61 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""Explain and conservatively diversify broad lexical navigation queries."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
from dataclasses import replace
|
|
9
|
+
from pathlib import PurePosixPath
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from attocode_intel.focused_evidence import task_terms, terms
|
|
13
|
+
from attocode_intel.test_ranking import is_test_path
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from attocode_intel._internal.integrations.context.semantic_search import SemanticSearchResult
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_QUERY_FILLER = frozenset({
|
|
20
|
+
"where", "which", "what", "why", "find", "locate", "show", "explain",
|
|
21
|
+
"implementation", "implemented", "handling", "handled",
|
|
22
|
+
})
|
|
23
|
+
_SOURCE_EXTENSIONS = frozenset({
|
|
24
|
+
".py", ".js", ".jsx", ".ts", ".tsx", ".go", ".rs", ".java",
|
|
25
|
+
".rb", ".c", ".cc", ".cpp", ".h", ".hpp", ".cs", ".swift",
|
|
26
|
+
".kt", ".scala", ".sh",
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def broad_rank_enabled() -> bool:
|
|
31
|
+
"""Keep the unproven lexical promotion out of default navigation."""
|
|
32
|
+
return os.environ.get("ATTOCODE_INTEL_BROAD_RERANK") == "1"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _default_file_diversity(
|
|
36
|
+
query: str, candidates: list[SemanticSearchResult], top_k: int,
|
|
37
|
+
file_filter: str,
|
|
38
|
+
) -> list[SemanticSearchResult]:
|
|
39
|
+
"""Return distinct files in original rank order when a full page exists.
|
|
40
|
+
|
|
41
|
+
This preserves the first-hit file and the order of all first file
|
|
42
|
+
occurrences. If the candidate pool cannot supply ``top_k`` distinct files,
|
|
43
|
+
retain the old page rather than silently returning fewer hits.
|
|
44
|
+
"""
|
|
45
|
+
if len(query_concepts(query)) < 2 or file_filter or re.search(r"\btests?\b", query, re.I):
|
|
46
|
+
return candidates[:top_k]
|
|
47
|
+
selected = []
|
|
48
|
+
seen = set()
|
|
49
|
+
for row in candidates:
|
|
50
|
+
if row.file_path not in seen:
|
|
51
|
+
selected.append(row)
|
|
52
|
+
seen.add(row.file_path)
|
|
53
|
+
if len(selected) == top_k:
|
|
54
|
+
return selected
|
|
55
|
+
return candidates[:top_k]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def query_concepts(query: str) -> tuple[str, ...]:
|
|
59
|
+
"""Retain task concepts, not question phrasing or explicit exclusions."""
|
|
60
|
+
positive, _ = task_terms(query)
|
|
61
|
+
return tuple(sorted(positive - _QUERY_FILLER))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def hit_evidence(query: str, result: SemanticSearchResult) -> dict[str, object]:
|
|
65
|
+
"""Report exactly which query concepts appear in identity and source."""
|
|
66
|
+
concepts = set(query_concepts(query))
|
|
67
|
+
identity = terms(f"{result.file_path} {result.name}")
|
|
68
|
+
evidence_text = result.text.split("\n", 1)[-1] if result.start_line else result.text
|
|
69
|
+
text_terms = terms(evidence_text)
|
|
70
|
+
in_identity = sorted(concepts & identity)
|
|
71
|
+
in_text = sorted(concepts & text_terms)
|
|
72
|
+
fields = []
|
|
73
|
+
if in_identity:
|
|
74
|
+
fields.append("identity")
|
|
75
|
+
if in_text:
|
|
76
|
+
fields.append("source_body" if result.start_line else "symbol_metadata")
|
|
77
|
+
return {
|
|
78
|
+
"matched_terms": sorted(set(in_identity) | set(in_text)),
|
|
79
|
+
"match_fields": fields,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _matches_exclusion(result: SemanticSearchResult, negative: set[str]) -> bool:
|
|
84
|
+
"""Keep explicit negative hints from receiving a full-coverage bonus."""
|
|
85
|
+
if not negative:
|
|
86
|
+
return False
|
|
87
|
+
identity = terms(f"{result.file_path} {result.name}")
|
|
88
|
+
source = terms(result.text)
|
|
89
|
+
return bool(source & negative) or any(
|
|
90
|
+
term == token or (len(term) >= 4 and term in token)
|
|
91
|
+
for term in negative for token in identity
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _component(path: str) -> str:
|
|
96
|
+
parts = PurePosixPath(path).parent.parts
|
|
97
|
+
if not parts:
|
|
98
|
+
return "."
|
|
99
|
+
if parts[0] == "packages" and len(parts) > 1:
|
|
100
|
+
return "/".join(parts[:2])
|
|
101
|
+
if parts[0] in {"src", "legacy"} and len(parts) > 2:
|
|
102
|
+
return "/".join(parts[:4])
|
|
103
|
+
return "/".join(parts[:2])
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def demote_tests(query: str, candidates: list[SemanticSearchResult]) -> list[SemanticSearchResult]:
|
|
107
|
+
"""Put test files after the other files, unless a short query asks for tests.
|
|
108
|
+
|
|
109
|
+
An issue is fixed in source files, and ``suggest_tests`` finds the tests. A long
|
|
110
|
+
issue often says "test" about its reproduction, so only a short query shows test
|
|
111
|
+
intent. The order in each group does not change.
|
|
112
|
+
"""
|
|
113
|
+
if re.search(r"\btests?\b", query, re.IGNORECASE) and len(terms(query)) <= 20:
|
|
114
|
+
return candidates
|
|
115
|
+
return sorted(candidates, key=lambda row: is_test_path(row.file_path))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _source_weight(path: str, test_intent: bool) -> float:
|
|
119
|
+
normalized = f"/{path.lower().replace('\\', '/')}"
|
|
120
|
+
if any(part in normalized for part in (
|
|
121
|
+
"/legacy/", "/lessons/", "/eval/", "/examples/", "/docs_src/",
|
|
122
|
+
)):
|
|
123
|
+
return 0.0
|
|
124
|
+
if not test_intent and any(part in normalized for part in ("/test/", "/tests/", "/docs/")):
|
|
125
|
+
return 0.0
|
|
126
|
+
return 1.0 if PurePosixPath(path).suffix.lower() in _SOURCE_EXTENSIONS else 0.0
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def rerank_broad_candidates(
|
|
130
|
+
query: str, candidates: list[SemanticSearchResult], top_k: int,
|
|
131
|
+
file_filter: str = "",
|
|
132
|
+
) -> list[SemanticSearchResult]:
|
|
133
|
+
"""Favor multi-concept source evidence while retaining ambiguous alternatives.
|
|
134
|
+
|
|
135
|
+
Only two-concept queries with a partial top hit are reordered. Longer
|
|
136
|
+
queries already have discriminating evidence; exhaustive source-body term
|
|
137
|
+
coverage tends to over-promote incidental docs and comments in them.
|
|
138
|
+
"""
|
|
139
|
+
if top_k <= 0 or not candidates:
|
|
140
|
+
return []
|
|
141
|
+
if not broad_rank_enabled():
|
|
142
|
+
return _default_file_diversity(query, candidates, top_k, file_filter)
|
|
143
|
+
concepts = query_concepts(query)
|
|
144
|
+
_, negative = task_terms(query)
|
|
145
|
+
if len(concepts) != 2:
|
|
146
|
+
return candidates[:top_k]
|
|
147
|
+
concept_set = set(concepts)
|
|
148
|
+
evidence = [hit_evidence(query, row) for row in candidates]
|
|
149
|
+
if concept_set <= set(evidence[0]["matched_terms"]):
|
|
150
|
+
return candidates[:top_k]
|
|
151
|
+
test_intent = bool(re.search(r"\btests?\b", query, re.IGNORECASE))
|
|
152
|
+
boostable = {
|
|
153
|
+
index for index, (row, item) in enumerate(zip(candidates, evidence, strict=True))
|
|
154
|
+
if concept_set <= set(item["matched_terms"])
|
|
155
|
+
and _source_weight(row.file_path, test_intent) > 0
|
|
156
|
+
and not _matches_exclusion(row, negative)
|
|
157
|
+
}
|
|
158
|
+
if not boostable:
|
|
159
|
+
return candidates[:top_k]
|
|
160
|
+
anchor = next(
|
|
161
|
+
(row for row in candidates if _source_weight(row.file_path, test_intent) > 0
|
|
162
|
+
and not _matches_exclusion(row, negative)),
|
|
163
|
+
None,
|
|
164
|
+
)
|
|
165
|
+
if anchor is not None:
|
|
166
|
+
anchor_component = _component(anchor.file_path)
|
|
167
|
+
local = {index for index in boostable
|
|
168
|
+
if _component(candidates[index].file_path) == anchor_component}
|
|
169
|
+
if local:
|
|
170
|
+
boostable = local
|
|
171
|
+
|
|
172
|
+
peak = max(row.score for row in candidates)
|
|
173
|
+
adjusted = []
|
|
174
|
+
for index, row in enumerate(candidates):
|
|
175
|
+
# The existing RRF score remains the tie-breaker. A complete match
|
|
176
|
+
# in the preferred component gets one peak-score bonus.
|
|
177
|
+
bonus = (
|
|
178
|
+
peak * _source_weight(row.file_path, test_intent)
|
|
179
|
+
if index in boostable
|
|
180
|
+
else 0.0
|
|
181
|
+
)
|
|
182
|
+
adjusted.append((replace(row, score=round(row.score + bonus, 6)), index))
|
|
183
|
+
adjusted.sort(key=lambda pair: (-pair[0].score, pair[1]))
|
|
184
|
+
|
|
185
|
+
if file_filter or test_intent:
|
|
186
|
+
return [row for row, _ in adjusted[:top_k]]
|
|
187
|
+
|
|
188
|
+
# Greedy file diversity prevents one implementation's class, methods and
|
|
189
|
+
# tests from monopolizing a broad query. It never discards a candidate.
|
|
190
|
+
selected: list[SemanticSearchResult] = []
|
|
191
|
+
seen_files: dict[str, int] = {}
|
|
192
|
+
while adjusted and len(selected) < top_k:
|
|
193
|
+
winner = max(
|
|
194
|
+
range(len(adjusted)),
|
|
195
|
+
key=lambda i: (
|
|
196
|
+
adjusted[i][0].score / math.pow(2.5, seen_files.get(adjusted[i][0].file_path, 0)),
|
|
197
|
+
-adjusted[i][1],
|
|
198
|
+
),
|
|
199
|
+
)
|
|
200
|
+
row, _ = adjusted.pop(winner)
|
|
201
|
+
effective_score = row.score / math.pow(2.5, seen_files.get(row.file_path, 0))
|
|
202
|
+
selected.append(replace(row, score=round(effective_score, 6)))
|
|
203
|
+
seen_files[row.file_path] = seen_files.get(row.file_path, 0) + 1
|
|
204
|
+
return selected
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def query_diagnostics(
|
|
208
|
+
query: str, candidates: list[SemanticSearchResult], file_filter: str = "",
|
|
209
|
+
) -> dict[str, object]:
|
|
210
|
+
"""Show ambiguity without pretending to know a user's intended subsystem."""
|
|
211
|
+
concepts = query_concepts(query)
|
|
212
|
+
_, negative = task_terms(query)
|
|
213
|
+
components: list[str] = []
|
|
214
|
+
if 2 <= len(concepts) <= 5:
|
|
215
|
+
for row in candidates:
|
|
216
|
+
if len(hit_evidence(query, row)["matched_terms"]) != len(concepts):
|
|
217
|
+
continue
|
|
218
|
+
if _matches_exclusion(row, negative):
|
|
219
|
+
continue
|
|
220
|
+
component = _component(row.file_path)
|
|
221
|
+
if component not in components:
|
|
222
|
+
components.append(component)
|
|
223
|
+
if len(components) >= 4:
|
|
224
|
+
break
|
|
225
|
+
ambiguous = not file_filter and len(components) >= 2
|
|
226
|
+
return {
|
|
227
|
+
"concepts": list(concepts[:5]),
|
|
228
|
+
"scope": file_filter or "workspace",
|
|
229
|
+
"ambiguous": ambiguous,
|
|
230
|
+
"matching_components": components[:3] if ambiguous else [],
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def next_search_top_k(candidate_count: int, requested: int, delivered: int) -> int | None:
|
|
235
|
+
"""Suggest a larger page only for candidates already in this search pool.
|
|
236
|
+
|
|
237
|
+
This is a fresh search request, not a stable cursor or a relevance claim.
|
|
238
|
+
A caller may have delivered fewer than requested due to its output budget.
|
|
239
|
+
"""
|
|
240
|
+
if candidate_count <= delivered or requested <= 0:
|
|
241
|
+
return None
|
|
242
|
+
return max(requested, min(candidate_count, max(24, requested * 2)))
|