codenib 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.
- codenib/__init__.py +62 -0
- codenib/__main__.py +7 -0
- codenib/_lazy.py +36 -0
- codenib/_version.py +26 -0
- codenib/agent/__init__.py +159 -0
- codenib/agent/agent_types.py +40 -0
- codenib/agent/boundary.py +129 -0
- codenib/agent/compile.py +219 -0
- codenib/agent/extract_agent.py +101 -0
- codenib/agent/harness.py +326 -0
- codenib/agent/history.py +242 -0
- codenib/agent/lsp_graph.py +878 -0
- codenib/agent/lsp_provider.py +484 -0
- codenib/agent/rerank_agent.py +419 -0
- codenib/agent/resource_guard.py +90 -0
- codenib/agent/route_context.py +391 -0
- codenib/agent/runner.py +2005 -0
- codenib/agent/runtime/__init__.py +16 -0
- codenib/agent/runtime/context.py +189 -0
- codenib/agent/runtime/trace.py +101 -0
- codenib/agent/skills/__init__.py +25 -0
- codenib/agent/skills/_graphnav.py +235 -0
- codenib/agent/skills/bm25_search/__init__.py +0 -0
- codenib/agent/skills/bm25_search/config.yaml +63 -0
- codenib/agent/skills/bm25_search/executor.py +80 -0
- codenib/agent/skills/bm25_search/skill.md +47 -0
- codenib/agent/skills/code_to_query/__init__.py +0 -0
- codenib/agent/skills/code_to_query/config.yaml +38 -0
- codenib/agent/skills/code_to_query/executor.py +69 -0
- codenib/agent/skills/code_to_query/skill.md +7 -0
- codenib/agent/skills/codenib_context/__init__.py +0 -0
- codenib/agent/skills/codenib_context/config.yaml +44 -0
- codenib/agent/skills/codenib_context/executor.py +184 -0
- codenib/agent/skills/codenib_context/skill.md +21 -0
- codenib/agent/skills/context.py +107 -0
- codenib/agent/skills/core.py +153 -0
- codenib/agent/skills/crossencoder_rerank/__init__.py +3 -0
- codenib/agent/skills/crossencoder_rerank/config.yaml +41 -0
- codenib/agent/skills/crossencoder_rerank/executor.py +62 -0
- codenib/agent/skills/crossencoder_rerank/skill.md +7 -0
- codenib/agent/skills/embedding_search/__init__.py +0 -0
- codenib/agent/skills/embedding_search/config.yaml +53 -0
- codenib/agent/skills/embedding_search/executor.py +57 -0
- codenib/agent/skills/embedding_search/skill.md +47 -0
- codenib/agent/skills/find_callees/__init__.py +0 -0
- codenib/agent/skills/find_callees/config.yaml +22 -0
- codenib/agent/skills/find_callees/executor.py +23 -0
- codenib/agent/skills/find_callees/skill.md +11 -0
- codenib/agent/skills/find_callers/__init__.py +0 -0
- codenib/agent/skills/find_callers/config.yaml +22 -0
- codenib/agent/skills/find_callers/executor.py +23 -0
- codenib/agent/skills/find_callers/skill.md +11 -0
- codenib/agent/skills/hybrid_search/__init__.py +0 -0
- codenib/agent/skills/hybrid_search/config.yaml +38 -0
- codenib/agent/skills/hybrid_search/executor.py +132 -0
- codenib/agent/skills/hybrid_search/skill.md +53 -0
- codenib/agent/skills/llm_rerank/__init__.py +0 -0
- codenib/agent/skills/llm_rerank/config.yaml +33 -0
- codenib/agent/skills/llm_rerank/executor.py +37 -0
- codenib/agent/skills/llm_rerank/skill.md +7 -0
- codenib/agent/skills/loader.py +240 -0
- codenib/agent/skills/lsp_definition/config.yaml +35 -0
- codenib/agent/skills/lsp_definition/executor.py +32 -0
- codenib/agent/skills/lsp_definition/skill.md +18 -0
- codenib/agent/skills/lsp_references/config.yaml +40 -0
- codenib/agent/skills/lsp_references/executor.py +34 -0
- codenib/agent/skills/lsp_references/skill.md +17 -0
- codenib/agent/skills/lsp_route/config.yaml +35 -0
- codenib/agent/skills/lsp_route/executor.py +34 -0
- codenib/agent/skills/lsp_route/skill.md +23 -0
- codenib/agent/skills/registry.py +136 -0
- codenib/agent/skills/repository_search/config.yaml +49 -0
- codenib/agent/skills/repository_search/executor.py +512 -0
- codenib/agent/skills/repository_search/skill.md +28 -0
- codenib/agent/skills/trace/__init__.py +0 -0
- codenib/agent/skills/trace/config.yaml +30 -0
- codenib/agent/skills/trace/executor.py +27 -0
- codenib/agent/skills/trace/skill.md +12 -0
- codenib/agent/skills/typecheck.py +302 -0
- codenib/agent/tool_schema.py +158 -0
- codenib/agent/tools/__init__.py +41 -0
- codenib/agent/tools/defaults.py +1045 -0
- codenib/agent/tools/spec.py +103 -0
- codenib/agent/utils.py +149 -0
- codenib/cli.py +1079 -0
- codenib/clients/__init__.py +5 -0
- codenib/clients/claude_agent.py +534 -0
- codenib/clients/codex_agent.py +314 -0
- codenib/code_chunker.py +730 -0
- codenib/code_chunking/__init__.py +113 -0
- codenib/code_chunking/base.py +592 -0
- codenib/code_chunking/cpp_chunker.py +278 -0
- codenib/code_chunking/csharp_chunker.py +210 -0
- codenib/code_chunking/go_chunker.py +213 -0
- codenib/code_chunking/java_chunker.py +188 -0
- codenib/code_chunking/js_chunker.py +251 -0
- codenib/code_chunking/kotlin_chunker.py +253 -0
- codenib/code_chunking/lua_chunker.py +94 -0
- codenib/code_chunking/php_chunker.py +204 -0
- codenib/code_chunking/python_chunker.py +267 -0
- codenib/code_chunking/ruby_chunker.py +198 -0
- codenib/code_chunking/rust_chunker.py +195 -0
- codenib/code_chunking/scala_chunker.py +182 -0
- codenib/code_chunking/swift_chunker.py +182 -0
- codenib/compat_pickle.py +48 -0
- codenib/compiler/__init__.py +93 -0
- codenib/compiler/index_builders.py +868 -0
- codenib/compiler/index_compiler.py +488 -0
- codenib/compiler/manifest.py +221 -0
- codenib/compiler/params.py +126 -0
- codenib/compiler/resources.py +267 -0
- codenib/compiler/skill_context.py +641 -0
- codenib/compiler/snapshot_store.py +311 -0
- codenib/compiler/verification.py +131 -0
- codenib/dataset/__init__.py +21 -0
- codenib/dataset/base.py +78 -0
- codenib/dataset/codenib_base.py +374 -0
- codenib/dataset/codenib_synthesis.py +540 -0
- codenib/dataset/collect/difficulty_classifier.py +511 -0
- codenib/dataset/collect/swebench_sample.py +766 -0
- codenib/dataset/gt_locate.py +831 -0
- codenib/dataset/local_json.py +184 -0
- codenib/dataset/locbench.py +254 -0
- codenib/dataset/swebench.py +344 -0
- codenib/dataset/swebench_multilingual.py +283 -0
- codenib/dataset/synthesize/__init__.py +71 -0
- codenib/dataset/synthesize/_agent.py +125 -0
- codenib/dataset/synthesize/_types.py +146 -0
- codenib/dataset/synthesize/context_loader.py +601 -0
- codenib/dataset/synthesize/query_curator.py +713 -0
- codenib/dataset/synthesize/query_synthesizer.py +546 -0
- codenib/dataset/synthesize/verifier.py +425 -0
- codenib/dataset/synthesize/vocab_guard.py +264 -0
- codenib/dataset/utils.py +380 -0
- codenib/eval/agent_runner/__init__.py +296 -0
- codenib/eval/agent_runner/baseline.py +299 -0
- codenib/eval/agent_runner/batch.py +176 -0
- codenib/eval/agent_runner/contexts.py +135 -0
- codenib/eval/agent_runner/feedback.py +135 -0
- codenib/eval/agent_runner/feedback_summary.py +326 -0
- codenib/eval/agent_runner/format_diagnostics.py +115 -0
- codenib/eval/agent_runner/live_lsp_provider.py +377 -0
- codenib/eval/agent_runner/loc_baseline.py +355 -0
- codenib/eval/agent_runner/lsp_agent_ab.py +577 -0
- codenib/eval/agent_runner/lsp_agent_study.py +408 -0
- codenib/eval/agent_runner/lsp_agent_study_analysis.py +411 -0
- codenib/eval/agent_runner/lsp_agent_study_artifacts.py +413 -0
- codenib/eval/agent_runner/lsp_agent_study_manifest.py +402 -0
- codenib/eval/agent_runner/lsp_agent_study_runner.py +694 -0
- codenib/eval/agent_runner/lsp_baseline.py +251 -0
- codenib/eval/agent_runner/lsp_latency.py +267 -0
- codenib/eval/agent_runner/lsp_provider_cli.py +273 -0
- codenib/eval/agent_runner/lsp_provider_validation.py +594 -0
- codenib/eval/agent_runner/lsp_readiness.py +167 -0
- codenib/eval/agent_runner/lsp_replay_benchmark.py +1072 -0
- codenib/eval/agent_runner/metrics.py +80 -0
- codenib/eval/agent_runner/orchestrator.py +173 -0
- codenib/eval/agent_runner/pareto.py +154 -0
- codenib/eval/agent_runner/prebuilt.py +484 -0
- codenib/eval/agent_runner/preload.py +219 -0
- codenib/eval/agent_runner/promotion.py +172 -0
- codenib/eval/agent_runner/query_sweep.py +432 -0
- codenib/eval/agent_runner/results.py +69 -0
- codenib/eval/agent_runner/scoring.py +134 -0
- codenib/eval/agent_runner/sweep.py +619 -0
- codenib/eval/agent_runner/sweep_config.py +160 -0
- codenib/eval/agent_runner/symbols.py +67 -0
- codenib/eval/agent_runner/trace_summary.py +405 -0
- codenib/eval/agent_runner/verify_expand.py +219 -0
- codenib/eval/artifact_bundle.py +322 -0
- codenib/eval/artifact_integrity.py +332 -0
- codenib/eval/artifact_manifest.py +236 -0
- codenib/eval/experiments/__init__.py +5 -0
- codenib/eval/experiments/lsp_agent_study_policy.py +55 -0
- codenib/eval/loc_agent_runner.py +37 -0
- codenib/eval/reports/__init__.py +5 -0
- codenib/eval/reports/cost_arm_report.py +810 -0
- codenib/eval/retrieval_eval.py +557 -0
- codenib/graph/__init__.py +44 -0
- codenib/graph/backend_alignment.py +184 -0
- codenib/graph/code_graph.py +1218 -0
- codenib/graph/dependency.py +229 -0
- codenib/graph/hierarchy.py +828 -0
- codenib/graph/incremental/__init__.py +15 -0
- codenib/graph/incremental/change_mgr.py +165 -0
- codenib/graph/incremental/graph_patcher.py +139 -0
- codenib/graph/incremental/lsp_client.py +1271 -0
- codenib/graph/incremental/patcher_base.py +1364 -0
- codenib/graph/incremental/patcher_cpp.py +796 -0
- codenib/graph/incremental/patcher_go.py +56 -0
- codenib/graph/incremental/patcher_python.py +43 -0
- codenib/graph/incremental/patcher_rust.py +113 -0
- codenib/graph/incremental/patcher_ts.py +49 -0
- codenib/graph/incremental/subgraph_mgr.py +1028 -0
- codenib/graph/layers.py +325 -0
- codenib/graph/roi_subgraph.py +394 -0
- codenib/graph/setup.py +689 -0
- codenib/graph/traverse_graph.py +237 -0
- codenib/index/__init__.py +42 -0
- codenib/index/embedding/__init__.py +48 -0
- codenib/index/embedding/builders.py +190 -0
- codenib/index/embedding/model_policy.py +62 -0
- codenib/index/embedding/prompt_registry.py +87 -0
- codenib/index/embedding/vector_store.py +1458 -0
- codenib/index/incremental/__init__.py +30 -0
- codenib/index/incremental/chunk_store.py +409 -0
- codenib/index/incremental/embeddings_cache.py +196 -0
- codenib/index/incremental/git_diff.py +221 -0
- codenib/index/incremental/index_updater.py +283 -0
- codenib/index/incremental/state.py +92 -0
- codenib/index/regex_idx/__init__.py +7 -0
- codenib/index/regex_idx/regex_idx.py +150 -0
- codenib/index/rerank/__init__.py +23 -0
- codenib/index/rerank/cross_encoder.py +356 -0
- codenib/index/sparse_idx/__init__.py +9 -0
- codenib/index/sparse_idx/bm25_index.py +724 -0
- codenib/index/trigram/__init__.py +17 -0
- codenib/index/trigram/zoekt_searcher.py +371 -0
- codenib/languages.py +1035 -0
- codenib/llm/__init__.py +33 -0
- codenib/llm/diagnostics.py +170 -0
- codenib/llm/litellm_chat.py +422 -0
- codenib/llm/options.py +139 -0
- codenib/llm/usage.py +182 -0
- codenib/log_utils.py +301 -0
- codenib/ls_index/__init__.py +17 -0
- codenib/ls_index/clangd_decode.py +912 -0
- codenib/ls_index/clangd_indexer.py +1400 -0
- codenib/ls_index/index_quality.py +442 -0
- codenib/ls_index/lsp_graph_decode.py +449 -0
- codenib/ls_index/lsp_indexer.py +246 -0
- codenib/ls_router.py +507 -0
- codenib/mcp/__init__.py +13 -0
- codenib/mcp/__main__.py +9 -0
- codenib/mcp/context.py +211 -0
- codenib/mcp/prompts.py +76 -0
- codenib/mcp/server.py +463 -0
- codenib/mcp/tools/__init__.py +9 -0
- codenib/mcp/tools/dependency.py +56 -0
- codenib/mcp/tools/lsp.py +119 -0
- codenib/mcp/tools/search.py +224 -0
- codenib/model/__init__.py +49 -0
- codenib/model/agentless_pipeline.py +484 -0
- codenib/model/bm25_retrieve_pipeline.py +100 -0
- codenib/model/dense_graph_expand_rerank_pipeline.py +300 -0
- codenib/model/embedding_retrieve_pipeline.py +152 -0
- codenib/model/graph_augmented_rerank_pipeline.py +19 -0
- codenib/model/graph_retrieve_pipeline.py +259 -0
- codenib/model/hybrid_retrieve_pipeline.py +256 -0
- codenib/model/retrieval_planner.py +377 -0
- codenib/model/retrieve_rerank_pipeline.py +1023 -0
- codenib/ops/expand.py +299 -0
- codenib/ops/filter.py +159 -0
- codenib/ops/rerank.py +246 -0
- codenib/ops/retrieve.py +293 -0
- codenib/ops/transform.py +34 -0
- codenib/paths.py +91 -0
- codenib/profiler.py +506 -0
- codenib/repository_filters.py +103 -0
- codenib/repository_summary.py +161 -0
- codenib/scip_interface/__init__.py +120 -0
- codenib/scip_interface/lsp_occurrence_index.py +327 -0
- codenib/scip_interface/rust_analyzer.py +29 -0
- codenib/scip_interface/scip-environment.yml +14 -0
- codenib/scip_interface/scip.proto +890 -0
- codenib/scip_interface/scip_decode_core.py +190 -0
- codenib/scip_interface/scip_decode_csharp.py +143 -0
- codenib/scip_interface/scip_decode_go.py +433 -0
- codenib/scip_interface/scip_decode_java.py +1117 -0
- codenib/scip_interface/scip_decode_php.py +194 -0
- codenib/scip_interface/scip_decode_python.py +400 -0
- codenib/scip_interface/scip_decode_ruby.py +464 -0
- codenib/scip_interface/scip_decode_rust.py +584 -0
- codenib/scip_interface/scip_decode_ts.py +542 -0
- codenib/scip_interface/scip_decode_utils.py +52 -0
- codenib/scip_interface/scip_indexer_base.py +728 -0
- codenib/scip_interface/scip_indexer_csharp.py +166 -0
- codenib/scip_interface/scip_indexer_go.py +164 -0
- codenib/scip_interface/scip_indexer_java.py +201 -0
- codenib/scip_interface/scip_indexer_php.py +548 -0
- codenib/scip_interface/scip_indexer_python.py +500 -0
- codenib/scip_interface/scip_indexer_ruby.py +369 -0
- codenib/scip_interface/scip_indexer_rust.py +183 -0
- codenib/scip_interface/scip_indexer_ts.py +616 -0
- codenib/scip_interface/scip_install.sh +8 -0
- codenib/scip_interface/scip_pb2.py +80 -0
- codenib/search.py +371 -0
- codenib/source_fingerprint.py +198 -0
- codenib/types.py +105 -0
- codenib/utils.py +93 -0
- codenib/web/__init__.py +9 -0
- codenib/web/app.py +467 -0
- codenib/web/codemap.py +753 -0
- codenib/web/commit_window.py +296 -0
- codenib/web/config.py +331 -0
- codenib/web/edge_label.py +332 -0
- codenib/web/frontend/assets/AskBar-Q_2zSw_D.js +31 -0
- codenib/web/frontend/assets/CodeGraph-C5zIOx4j.js +3 -0
- codenib/web/frontend/assets/CodePanel-BE7Wg1wI.js +1 -0
- codenib/web/frontend/assets/Codemap-C5Xm7Go_.js +2 -0
- codenib/web/frontend/assets/GraphView-CBBbxS9a.js +2 -0
- codenib/web/frontend/assets/Header-CUW7gfQl.js +1 -0
- codenib/web/frontend/assets/HighlightedBlock-H7FGwbAI.js +1 -0
- codenib/web/frontend/assets/HighlightedCode-CTRFPFV9.js +2 -0
- codenib/web/frontend/assets/Mermaid-NhydXLyh.js +303 -0
- codenib/web/frontend/assets/api-DMyba6Hn.js +1 -0
- codenib/web/frontend/assets/arc-Cj6TUG7b.js +1 -0
- codenib/web/frontend/assets/architectureDiagram-3BPJPVTR-BXC7SbpZ.js +36 -0
- codenib/web/frontend/assets/blockDiagram-GPEHLZMM-BYhhgH_O.js +132 -0
- codenib/web/frontend/assets/c4Diagram-AAUBKEIU-BPe9Xb1K.js +10 -0
- codenib/web/frontend/assets/channel-DGptmZnr.js +1 -0
- codenib/web/frontend/assets/chunk-2J33WTMH-mJuoTx1I.js +1 -0
- codenib/web/frontend/assets/chunk-4BX2VUAB-DyIPfnHV.js +1 -0
- codenib/web/frontend/assets/chunk-55IACEB6-C8bSn9Qq.js +1 -0
- codenib/web/frontend/assets/chunk-727SXJPM-CgiBqZFm.js +206 -0
- codenib/web/frontend/assets/chunk-AQP2D5EJ-DOOlLotN.js +231 -0
- codenib/web/frontend/assets/chunk-FMBD7UC4-mf47mSz2.js +15 -0
- codenib/web/frontend/assets/chunk-ND2GUHAM-D6lobpla.js +1 -0
- codenib/web/frontend/assets/chunk-QZHKN3VN-D9a00sWs.js +1 -0
- codenib/web/frontend/assets/classDiagram-4FO5ZUOK-wDtvnBsq.js +1 -0
- codenib/web/frontend/assets/classDiagram-v2-Q7XG4LA2-wDtvnBsq.js +1 -0
- codenib/web/frontend/assets/cose-bilkent-S5V4N54A-JwC1FU9v.js +1 -0
- codenib/web/frontend/assets/cytoscape.esm-CkSuTymj.js +321 -0
- codenib/web/frontend/assets/dagre-BM42HDAG-BTm6Sb-x.js +4 -0
- codenib/web/frontend/assets/defaultLocale-DX6XiGOO.js +1 -0
- codenib/web/frontend/assets/diagram-2AECGRRQ-C7XNwfvk.js +43 -0
- codenib/web/frontend/assets/diagram-5GNKFQAL-DcLriIgZ.js +10 -0
- codenib/web/frontend/assets/diagram-KO2AKTUF-Bo-6Bpfo.js +3 -0
- codenib/web/frontend/assets/diagram-LMA3HP47-M4Nh-qq-.js +24 -0
- codenib/web/frontend/assets/diagram-OG6HWLK6-BUT1QVEf.js +24 -0
- codenib/web/frontend/assets/erDiagram-TEJ5UH35-DViEMoeP.js +85 -0
- codenib/web/frontend/assets/flowDiagram-I6XJVG4X-DjBB1gSM.js +162 -0
- codenib/web/frontend/assets/ganttDiagram-6RSMTGT7-Drhb89TN.js +292 -0
- codenib/web/frontend/assets/gitGraphDiagram-PVQCEYII-CwqblmoY.js +106 -0
- codenib/web/frontend/assets/graph--OzhPTMs.js +1 -0
- codenib/web/frontend/assets/highlight-CDab0zVI.css +1 -0
- codenib/web/frontend/assets/highlight-CnfLc-V2.js +5 -0
- codenib/web/frontend/assets/index-BHP8c3Tq.js +9 -0
- codenib/web/frontend/assets/index-CKJrqu86.css +1 -0
- codenib/web/frontend/assets/infoDiagram-5YYISTIA-BKq62LUG.js +2 -0
- codenib/web/frontend/assets/init-Gi6I4Gst.js +1 -0
- codenib/web/frontend/assets/ishikawaDiagram-YF4QCWOH-DBAgfp9d.js +70 -0
- codenib/web/frontend/assets/journeyDiagram-JHISSGLW-DwHStEV9.js +139 -0
- codenib/web/frontend/assets/kanban-definition-UN3LZRKU-CWPLLTQn.js +89 -0
- codenib/web/frontend/assets/katex-HP8lGamR.js +257 -0
- codenib/web/frontend/assets/layout-SsrduOYp.js +1 -0
- codenib/web/frontend/assets/linear-DNcGZFnN.js +1 -0
- codenib/web/frontend/assets/mindmap-definition-RKZ34NQL-FZHYTpdO.js +96 -0
- codenib/web/frontend/assets/ordinal-Cboi1Yqb.js +1 -0
- codenib/web/frontend/assets/page-Bn-Q8MBy.js +6 -0
- codenib/web/frontend/assets/page-CESv5Ezw.js +2 -0
- codenib/web/frontend/assets/page-CHsElUu2.js +1 -0
- codenib/web/frontend/assets/page-D1WhIRzi.js +1 -0
- codenib/web/frontend/assets/pieDiagram-4H26LBE5-DKlC7xtb.js +30 -0
- codenib/web/frontend/assets/quadrantDiagram-W4KKPZXB-DldkGUZS.js +7 -0
- codenib/web/frontend/assets/requirementDiagram-4Y6WPE33-Dndb6w-j.js +84 -0
- codenib/web/frontend/assets/sankeyDiagram-5OEKKPKP-B2ewtJAC.js +40 -0
- codenib/web/frontend/assets/sequenceDiagram-3UESZ5HK-2N2KbYFt.js +162 -0
- codenib/web/frontend/assets/stateDiagram-AJRCARHV-CLwUuVlz.js +1 -0
- codenib/web/frontend/assets/stateDiagram-v2-BHNVJYJU-IiZdW_Og.js +1 -0
- codenib/web/frontend/assets/timeline-definition-PNZ67QCA-D_IdllIp.js +120 -0
- codenib/web/frontend/assets/vennDiagram-CIIHVFJN-CSU7pI9M.js +34 -0
- codenib/web/frontend/assets/wardley-L42UT6IY-Bv1Eg1Al.js +161 -0
- codenib/web/frontend/assets/wardleyDiagram-YWT4CUSO-Di3bYwLm.js +78 -0
- codenib/web/frontend/assets/xychartDiagram-2RQKCTM6-CPHWEBiN.js +7 -0
- codenib/web/frontend/codenib-icon.svg +34 -0
- codenib/web/frontend/index.html +29 -0
- codenib/web/frontend/runtime-config.js +1 -0
- codenib/web/launcher.py +252 -0
- codenib/web/local.py +196 -0
- codenib/web/repo_registry.py +561 -0
- codenib/web/schemas.py +329 -0
- codenib/web/static_server.py +213 -0
- codenib/wiki/__init__.py +15 -0
- codenib/wiki/agent_wiki.py +4665 -0
- codenib/wiki/builder.py +849 -0
- codenib/wiki/evidence.py +905 -0
- codenib/wiki/narrator.py +258 -0
- codenib/wiki/outline.py +1432 -0
- codenib/wiki/quality.py +932 -0
- codenib-0.1.0.dist-info/METADATA +293 -0
- codenib-0.1.0.dist-info/RECORD +386 -0
- codenib-0.1.0.dist-info/WHEEL +5 -0
- codenib-0.1.0.dist-info/entry_points.txt +13 -0
- codenib-0.1.0.dist-info/licenses/LICENSE +201 -0
- codenib-0.1.0.dist-info/top_level.txt +1 -0
codenib/__init__.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Public CodeNib API.
|
|
6
|
+
|
|
7
|
+
Exports are resolved lazily so importing :mod:`codenib` or starting the CLI
|
|
8
|
+
does not initialize optional graph, embedding, and agent runtimes.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from ._lazy import exported_dir, load_export
|
|
16
|
+
from ._version import __version__
|
|
17
|
+
|
|
18
|
+
_EXPORTS = {
|
|
19
|
+
"LSIndexer": ("codenib.ls_router", "LSIndexer"),
|
|
20
|
+
"CodeGraph": ("codenib.graph.code_graph", "CodeGraph"),
|
|
21
|
+
"BM25CodeIndexer": (
|
|
22
|
+
"codenib.index.sparse_idx.bm25_index",
|
|
23
|
+
"BM25CodeIndexer",
|
|
24
|
+
),
|
|
25
|
+
"KeywordExtractor": ("codenib.agent.extract_agent", "KeywordExtractor"),
|
|
26
|
+
"CodeSearchEngine": ("codenib.search", "CodeSearchEngine"),
|
|
27
|
+
"RerankAgent": ("codenib.agent.rerank_agent", "RerankAgent"),
|
|
28
|
+
"CodeChunker": ("codenib.code_chunker", "CodeChunker"),
|
|
29
|
+
"RepoChunkingConfig": ("codenib.code_chunker", "RepoChunkingConfig"),
|
|
30
|
+
"RegexNodeIndex": ("codenib.index.regex_idx", "RegexNodeIndex"),
|
|
31
|
+
"CodeVectorStore": (
|
|
32
|
+
"codenib.index.embedding.vector_store",
|
|
33
|
+
"CodeVectorStore",
|
|
34
|
+
),
|
|
35
|
+
"create_code_vector_store": (
|
|
36
|
+
"codenib.index.embedding.vector_store",
|
|
37
|
+
"create_code_vector_store",
|
|
38
|
+
),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"__version__",
|
|
43
|
+
"LSIndexer",
|
|
44
|
+
"CodeGraph",
|
|
45
|
+
"BM25CodeIndexer",
|
|
46
|
+
"KeywordExtractor",
|
|
47
|
+
"CodeSearchEngine",
|
|
48
|
+
"RerankAgent",
|
|
49
|
+
"CodeChunker",
|
|
50
|
+
"RepoChunkingConfig",
|
|
51
|
+
"RegexNodeIndex",
|
|
52
|
+
"CodeVectorStore",
|
|
53
|
+
"create_code_vector_store",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def __getattr__(name: str) -> Any:
|
|
58
|
+
return load_export(globals(), _EXPORTS, name)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def __dir__() -> list[str]:
|
|
62
|
+
return exported_dir(globals(), _EXPORTS)
|
codenib/__main__.py
ADDED
codenib/_lazy.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Small helper for preserving package APIs without eager imports."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from importlib import import_module
|
|
10
|
+
from typing import Any, Mapping, MutableMapping
|
|
11
|
+
|
|
12
|
+
LazyExports = Mapping[str, tuple[str, str]]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def load_export(
|
|
16
|
+
namespace: MutableMapping[str, Any],
|
|
17
|
+
exports: LazyExports,
|
|
18
|
+
name: str,
|
|
19
|
+
) -> Any:
|
|
20
|
+
"""Import, cache, and return one declared package export."""
|
|
21
|
+
target = exports.get(name)
|
|
22
|
+
if target is None:
|
|
23
|
+
module_name = namespace.get("__name__", "module")
|
|
24
|
+
raise AttributeError(f"module {module_name!r} has no attribute {name!r}")
|
|
25
|
+
module_name, attribute = target
|
|
26
|
+
value = getattr(import_module(module_name), attribute)
|
|
27
|
+
namespace[name] = value
|
|
28
|
+
return value
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def exported_dir(namespace: Mapping[str, Any], exports: LazyExports) -> list[str]:
|
|
32
|
+
"""Include lazy exports in ``dir(package)``."""
|
|
33
|
+
return sorted(set(namespace) | set(exports))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = ["LazyExports", "exported_dir", "load_export"]
|
codenib/_version.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Installed CodeNib version.
|
|
6
|
+
|
|
7
|
+
``pyproject.toml`` is the only authored version source. Package metadata makes
|
|
8
|
+
that value available at runtime without importing optional CodeNib subsystems.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from importlib import metadata
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def package_version() -> str:
|
|
17
|
+
"""Return the installed distribution version."""
|
|
18
|
+
try:
|
|
19
|
+
return metadata.version("codenib")
|
|
20
|
+
except metadata.PackageNotFoundError:
|
|
21
|
+
return "0+unknown"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__version__ = package_version()
|
|
25
|
+
|
|
26
|
+
__all__ = ["__version__", "package_version"]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Agent package consolidating agent utilities and implementations."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from .._lazy import exported_dir, load_export
|
|
12
|
+
|
|
13
|
+
_EXPORTS = {
|
|
14
|
+
"AgentResult": ("codenib.agent.agent_types", "AgentResult"),
|
|
15
|
+
"ToolCallRecord": ("codenib.agent.agent_types", "ToolCallRecord"),
|
|
16
|
+
"KeywordExtraction": ("codenib.agent.extract_agent", "KeywordExtraction"),
|
|
17
|
+
"KeywordExtractor": ("codenib.agent.extract_agent", "KeywordExtractor"),
|
|
18
|
+
"extract_keywords_from_statement": (
|
|
19
|
+
"codenib.agent.extract_agent",
|
|
20
|
+
"extract_keywords_from_statement",
|
|
21
|
+
),
|
|
22
|
+
"AgentHarnessSpec": ("codenib.agent.harness", "AgentHarnessSpec"),
|
|
23
|
+
"AgentRunAccumulator": ("codenib.agent.harness", "AgentRunAccumulator"),
|
|
24
|
+
"agent_working_directory": (
|
|
25
|
+
"codenib.agent.harness",
|
|
26
|
+
"agent_working_directory",
|
|
27
|
+
),
|
|
28
|
+
"run_agent_in_directory": (
|
|
29
|
+
"codenib.agent.harness",
|
|
30
|
+
"run_agent_in_directory",
|
|
31
|
+
),
|
|
32
|
+
"PlainChatHistory": ("codenib.agent.history", "PlainChatHistory"),
|
|
33
|
+
"TokenBudgetedChatHistory": (
|
|
34
|
+
"codenib.agent.history",
|
|
35
|
+
"TokenBudgetedChatHistory",
|
|
36
|
+
),
|
|
37
|
+
"count_message_tokens": ("codenib.agent.history", "count_message_tokens"),
|
|
38
|
+
"LSPProviderMetadata": (
|
|
39
|
+
"codenib.agent.lsp_provider",
|
|
40
|
+
"LSPProviderMetadata",
|
|
41
|
+
),
|
|
42
|
+
"LSPProviderNodes": ("codenib.agent.lsp_provider", "LSPProviderNodes"),
|
|
43
|
+
"StaticLSPProvider": ("codenib.agent.lsp_provider", "StaticLSPProvider"),
|
|
44
|
+
"lsp_result_metadata": (
|
|
45
|
+
"codenib.agent.lsp_provider",
|
|
46
|
+
"lsp_result_metadata",
|
|
47
|
+
),
|
|
48
|
+
"RerankAgent": ("codenib.agent.rerank_agent", "RerankAgent"),
|
|
49
|
+
"RerankResult": ("codenib.agent.rerank_agent", "RerankResult"),
|
|
50
|
+
"rerank_nodes_with_query": (
|
|
51
|
+
"codenib.agent.rerank_agent",
|
|
52
|
+
"rerank_nodes_with_query",
|
|
53
|
+
),
|
|
54
|
+
"LSPRouteContext": ("codenib.agent.route_context", "LSPRouteContext"),
|
|
55
|
+
"build_lsp_route_context": (
|
|
56
|
+
"codenib.agent.route_context",
|
|
57
|
+
"build_lsp_route_context",
|
|
58
|
+
),
|
|
59
|
+
"canonical_lsp_route_args": (
|
|
60
|
+
"codenib.agent.route_context",
|
|
61
|
+
"canonical_lsp_route_args",
|
|
62
|
+
),
|
|
63
|
+
"extract_lsp_symbol_seeds": (
|
|
64
|
+
"codenib.agent.route_context",
|
|
65
|
+
"extract_lsp_symbol_seeds",
|
|
66
|
+
),
|
|
67
|
+
"filter_lsp_symbol_seeds": (
|
|
68
|
+
"codenib.agent.route_context",
|
|
69
|
+
"filter_lsp_symbol_seeds",
|
|
70
|
+
),
|
|
71
|
+
"fingerprint_lsp_route_nodes": (
|
|
72
|
+
"codenib.agent.route_context",
|
|
73
|
+
"fingerprint_lsp_route_nodes",
|
|
74
|
+
),
|
|
75
|
+
"is_specific_lsp_symbol_seed": (
|
|
76
|
+
"codenib.agent.route_context",
|
|
77
|
+
"is_specific_lsp_symbol_seed",
|
|
78
|
+
),
|
|
79
|
+
"normalize_lsp_route_seed_policy": (
|
|
80
|
+
"codenib.agent.route_context",
|
|
81
|
+
"normalize_lsp_route_seed_policy",
|
|
82
|
+
),
|
|
83
|
+
"render_lsp_route_context": (
|
|
84
|
+
"codenib.agent.route_context",
|
|
85
|
+
"render_lsp_route_context",
|
|
86
|
+
),
|
|
87
|
+
"AgentRunner": ("codenib.agent.runner", "AgentRunner"),
|
|
88
|
+
"CodeNibAgentOptions": ("codenib.agent.runner", "CodeNibAgentOptions"),
|
|
89
|
+
"compile_repo": ("codenib.agent.runner", "compile_repo"),
|
|
90
|
+
"has_localization_contract": (
|
|
91
|
+
"codenib.agent.runner",
|
|
92
|
+
"has_localization_contract",
|
|
93
|
+
),
|
|
94
|
+
"query": ("codenib.agent.runner", "query"),
|
|
95
|
+
"AGENT_TRACE_SCHEMA_VERSION": (
|
|
96
|
+
"codenib.agent.runtime",
|
|
97
|
+
"AGENT_TRACE_SCHEMA_VERSION",
|
|
98
|
+
),
|
|
99
|
+
"AgentRunTrace": ("codenib.agent.runtime", "AgentRunTrace"),
|
|
100
|
+
"AgentTraceEvent": ("codenib.agent.runtime", "AgentTraceEvent"),
|
|
101
|
+
"ContextLedger": ("codenib.agent.runtime", "ContextLedger"),
|
|
102
|
+
"ContextLedgerEntry": ("codenib.agent.runtime", "ContextLedgerEntry"),
|
|
103
|
+
"registry_to_tools": ("codenib.agent.tool_schema", "registry_to_tools"),
|
|
104
|
+
"skill_to_tool_schema": (
|
|
105
|
+
"codenib.agent.tool_schema",
|
|
106
|
+
"skill_to_tool_schema",
|
|
107
|
+
),
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
__all__ = [
|
|
111
|
+
"AgentResult",
|
|
112
|
+
"AgentRunTrace",
|
|
113
|
+
"AgentRunAccumulator",
|
|
114
|
+
"AgentTraceEvent",
|
|
115
|
+
"AgentRunner",
|
|
116
|
+
"AGENT_TRACE_SCHEMA_VERSION",
|
|
117
|
+
"AgentHarnessSpec",
|
|
118
|
+
"CodeNibAgentOptions",
|
|
119
|
+
"ContextLedger",
|
|
120
|
+
"ContextLedgerEntry",
|
|
121
|
+
"KeywordExtraction",
|
|
122
|
+
"KeywordExtractor",
|
|
123
|
+
"LSPRouteContext",
|
|
124
|
+
"LSPProviderMetadata",
|
|
125
|
+
"LSPProviderNodes",
|
|
126
|
+
"PlainChatHistory",
|
|
127
|
+
"RerankAgent",
|
|
128
|
+
"RerankResult",
|
|
129
|
+
"TokenBudgetedChatHistory",
|
|
130
|
+
"ToolCallRecord",
|
|
131
|
+
"StaticLSPProvider",
|
|
132
|
+
"agent_working_directory",
|
|
133
|
+
"compile_repo",
|
|
134
|
+
"count_message_tokens",
|
|
135
|
+
"build_lsp_route_context",
|
|
136
|
+
"canonical_lsp_route_args",
|
|
137
|
+
"extract_keywords_from_statement",
|
|
138
|
+
"extract_lsp_symbol_seeds",
|
|
139
|
+
"filter_lsp_symbol_seeds",
|
|
140
|
+
"fingerprint_lsp_route_nodes",
|
|
141
|
+
"has_localization_contract",
|
|
142
|
+
"is_specific_lsp_symbol_seed",
|
|
143
|
+
"lsp_result_metadata",
|
|
144
|
+
"normalize_lsp_route_seed_policy",
|
|
145
|
+
"query",
|
|
146
|
+
"rerank_nodes_with_query",
|
|
147
|
+
"render_lsp_route_context",
|
|
148
|
+
"registry_to_tools",
|
|
149
|
+
"run_agent_in_directory",
|
|
150
|
+
"skill_to_tool_schema",
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def __getattr__(name: str) -> Any:
|
|
155
|
+
return load_export(globals(), _EXPORTS, name)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def __dir__() -> list[str]:
|
|
159
|
+
return exported_dir(globals(), _EXPORTS)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Data types for the agent runner."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
from ..llm.usage import TokenUsage, UsageRecord
|
|
13
|
+
from .runtime.trace import AgentRunTrace
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ToolCallRecord:
|
|
18
|
+
"""Record of a single tool invocation during an agent run."""
|
|
19
|
+
|
|
20
|
+
tool_call_id: str
|
|
21
|
+
skill_id: str
|
|
22
|
+
arguments: Dict[str, Any]
|
|
23
|
+
resolved_arguments: Optional[Dict[str, Any]] = None
|
|
24
|
+
result: Any = None
|
|
25
|
+
duration_ms: float = 0.0
|
|
26
|
+
error: Optional[str] = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class AgentResult:
|
|
31
|
+
"""Outcome of ``AgentRunner.run()``."""
|
|
32
|
+
|
|
33
|
+
answer: str
|
|
34
|
+
tool_calls: List[ToolCallRecord] = field(default_factory=list)
|
|
35
|
+
messages: List[Dict[str, Any]] = field(default_factory=list)
|
|
36
|
+
total_turns: int = 0
|
|
37
|
+
total_duration_ms: float = 0.0
|
|
38
|
+
usage: Optional[TokenUsage] = None
|
|
39
|
+
usage_records: List[UsageRecord] = field(default_factory=list)
|
|
40
|
+
trace: Optional[AgentRunTrace] = None
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Agent-boundary line-numbering conversion (issue #153).
|
|
6
|
+
|
|
7
|
+
Internal representations are uniformly **0-based**: BM25 docs, FAISS
|
|
8
|
+
metadata, symbol-graph anchors, and the tree-sitter ``CodeChunk`` all count
|
|
9
|
+
lines from 0. The *agent boundary* is **1-based outward** -- line numbers
|
|
10
|
+
shown to, and accepted back from, the LLM are 1-based, mirroring the
|
|
11
|
+
``CodeLocation`` convention already used at the dataset/HuggingFace boundary
|
|
12
|
+
(see ``_chunk_to_code_block`` in ``dataset/gt_locate.py``, which does the
|
|
13
|
+
same ``+1`` once).
|
|
14
|
+
|
|
15
|
+
Without a single conversion site there is a silent 0/1 split *inside one
|
|
16
|
+
result*: a ``bm25_search`` hit renders its ``content`` gutter 1-based (via
|
|
17
|
+
``wrap_code_snippet(start_line + 1, ...)``) while its structured
|
|
18
|
+
``start_line`` stays 0-based, so an LLM that reads "line 42" from the
|
|
19
|
+
snippet and feeds it back as a seed into ``graph_expand`` hits an
|
|
20
|
+
off-by-one that never raises.
|
|
21
|
+
|
|
22
|
+
Two helpers, one conversion each:
|
|
23
|
+
|
|
24
|
+
- :func:`to_agent_repr` -- serialize a result node for the LLM (``+1``).
|
|
25
|
+
- :func:`from_agent_repr` -- parse a line number coming back (``-1``).
|
|
26
|
+
|
|
27
|
+
Internals stay 0-based; only these two functions touch the offset.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
from typing import Any, Dict, Optional
|
|
33
|
+
|
|
34
|
+
# The LLM sees 1-based lines; every internal index is 0-based.
|
|
35
|
+
AGENT_LINE_OFFSET = 1
|
|
36
|
+
|
|
37
|
+
# Structured fields carrying a line number on a result node.
|
|
38
|
+
_LINE_FIELDS = ("start_line", "end_line")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _is_int_line(val: Any) -> bool:
|
|
42
|
+
"""Whether *val* is a real integer line number.
|
|
43
|
+
|
|
44
|
+
``bool`` is an ``int`` subclass; exclude it defensively so a stray
|
|
45
|
+
``True``/``False`` is never shifted as if it were line ``1``/``0``.
|
|
46
|
+
"""
|
|
47
|
+
return isinstance(val, int) and not isinstance(val, bool)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def is_line_bearing(obj: Any) -> bool:
|
|
51
|
+
"""Whether *obj* is a result node that carries line-number fields.
|
|
52
|
+
|
|
53
|
+
Used to decide whether :func:`to_agent_repr` should be applied during
|
|
54
|
+
serialization; non-node results (bare strings, scores, dicts without
|
|
55
|
+
line fields) are left untouched.
|
|
56
|
+
"""
|
|
57
|
+
if isinstance(obj, dict):
|
|
58
|
+
return "start_line" in obj or "end_line" in obj
|
|
59
|
+
return hasattr(obj, "start_line") or hasattr(obj, "end_line")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def to_agent_repr(node: Any) -> Dict[str, Any]:
|
|
63
|
+
"""Serialize a result node to a 1-based dict for the LLM.
|
|
64
|
+
|
|
65
|
+
Accepts a pydantic ``NodeInfo`` / ``QueriedNode``, a plain object with
|
|
66
|
+
``__dict__``, or a mapping. Returns a plain dict with ``start_line`` /
|
|
67
|
+
``end_line`` shifted ``+1`` (0-based -> 1-based). ``None`` line values
|
|
68
|
+
are preserved; all other fields pass through unchanged.
|
|
69
|
+
"""
|
|
70
|
+
data = _as_dict(node)
|
|
71
|
+
for fld in _LINE_FIELDS:
|
|
72
|
+
val = data.get(fld)
|
|
73
|
+
if _is_int_line(val):
|
|
74
|
+
data[fld] = val + AGENT_LINE_OFFSET
|
|
75
|
+
return data
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def from_agent_repr(line: Optional[int]) -> Optional[int]:
|
|
79
|
+
"""Convert a single 1-based line number from the LLM to 0-based.
|
|
80
|
+
|
|
81
|
+
``None`` passes through. A malformed seed (the LLM emitting ``0`` or a
|
|
82
|
+
negative, which is not a valid 1-based line) is clamped at ``0`` so it
|
|
83
|
+
can never produce a negative internal index.
|
|
84
|
+
"""
|
|
85
|
+
if line is None or isinstance(line, bool):
|
|
86
|
+
return line
|
|
87
|
+
converted = int(line) - AGENT_LINE_OFFSET
|
|
88
|
+
return converted if converted >= 0 else 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def from_agent_repr_arg(value: Any) -> Any:
|
|
92
|
+
"""Apply :func:`from_agent_repr` across a whole tool argument.
|
|
93
|
+
|
|
94
|
+
Handles the shapes a line-bearing skill argument can take:
|
|
95
|
+
|
|
96
|
+
- a scalar line number,
|
|
97
|
+
- a list/tuple of line numbers,
|
|
98
|
+
- a list of ``[start, end]`` pairs, or
|
|
99
|
+
- ``{"start_line": ..., "end_line": ...}`` range dicts.
|
|
100
|
+
|
|
101
|
+
Any other shape passes through unchanged. This is the input-side
|
|
102
|
+
counterpart wired into :class:`~codenib.agent.runner.AgentRunner` for
|
|
103
|
+
skill inputs marked ``is_line_number`` (e.g. ``graph_expand`` ranges,
|
|
104
|
+
``read_code_block``).
|
|
105
|
+
"""
|
|
106
|
+
if value is None or isinstance(value, bool):
|
|
107
|
+
return value
|
|
108
|
+
if isinstance(value, int):
|
|
109
|
+
return from_agent_repr(value)
|
|
110
|
+
if isinstance(value, (list, tuple)):
|
|
111
|
+
return type(value)(from_agent_repr_arg(v) for v in value)
|
|
112
|
+
if isinstance(value, dict):
|
|
113
|
+
out = dict(value)
|
|
114
|
+
for fld in _LINE_FIELDS:
|
|
115
|
+
if _is_int_line(out.get(fld)):
|
|
116
|
+
out[fld] = from_agent_repr(out[fld])
|
|
117
|
+
return out
|
|
118
|
+
return value
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _as_dict(node: Any) -> Dict[str, Any]:
|
|
122
|
+
"""Best-effort conversion of a result node to a mutable dict."""
|
|
123
|
+
if isinstance(node, dict):
|
|
124
|
+
return dict(node)
|
|
125
|
+
if hasattr(node, "model_dump"):
|
|
126
|
+
return node.model_dump(exclude_none=True)
|
|
127
|
+
if hasattr(node, "__dict__"):
|
|
128
|
+
return dict(node.__dict__)
|
|
129
|
+
return {"value": node}
|
codenib/agent/compile.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 CodeNib Contributors
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""Agent compile: query-time skill selection.
|
|
6
|
+
|
|
7
|
+
Implements the lookup mechanism from issue #133 (RFC: Agent compile).
|
|
8
|
+
At agent entry, ``classify(query, session_ctx)`` produces a ``Scenario``;
|
|
9
|
+
``agent_compile`` then looks the scenario up in a ``compile_table`` and
|
|
10
|
+
returns the skill subset the agent is allowed to call this turn.
|
|
11
|
+
|
|
12
|
+
The classifier is deterministic by design. LLM-driven scenario
|
|
13
|
+
classification was explicitly de-scoped in the v2 RFC (open question 3):
|
|
14
|
+
start with rules, revisit once Phase 2 data is in. Two dimensions are
|
|
15
|
+
runtime-computable without GT access:
|
|
16
|
+
|
|
17
|
+
* ``language`` — taken from ``SessionContext.primary_language`` (which
|
|
18
|
+
upstream loaders fill from the dataset row or repo metadata).
|
|
19
|
+
* ``has_stacktrace`` — regex sweep over the query text.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import logging
|
|
26
|
+
import re
|
|
27
|
+
from dataclasses import dataclass
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Dict, FrozenSet, Iterable, Mapping, Optional, Union
|
|
30
|
+
|
|
31
|
+
from ..compiler.params import SessionContext
|
|
32
|
+
from ..languages import (
|
|
33
|
+
agent_language_aliases,
|
|
34
|
+
normalize_agent_language,
|
|
35
|
+
supported_agent_languages,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
SUPPORTED_LANGUAGES: FrozenSet[str] = supported_agent_languages()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Stack-trace regexes. Each pattern matches a *structural* marker that only
|
|
45
|
+
# appears in a real captured trace — not in user prose mentioning the word
|
|
46
|
+
# "traceback" or "panic". Patterns are anchored where the runtime emits them
|
|
47
|
+
# (line start) and use ``re.MULTILINE`` because problem_statement bodies
|
|
48
|
+
# typically embed traces inline.
|
|
49
|
+
_STACKTRACE_PATTERNS = (
|
|
50
|
+
# Python — exact runtime banner
|
|
51
|
+
re.compile(r"Traceback \(most recent call last\):"),
|
|
52
|
+
# Rust — panic header
|
|
53
|
+
re.compile(r"thread '[^']+' panicked at", re.IGNORECASE),
|
|
54
|
+
re.compile(r"\bpanicked at\b 'try '", re.IGNORECASE), # older rust style
|
|
55
|
+
# Go — runtime panic line + a goroutine frame
|
|
56
|
+
re.compile(r"^panic: ", re.MULTILINE),
|
|
57
|
+
re.compile(r"^goroutine \d+ \[", re.MULTILINE),
|
|
58
|
+
# JS / TS / Node — stack frames " at name (file.js:42[:col])"
|
|
59
|
+
re.compile(
|
|
60
|
+
r"^\s+at\s+\S+\s*\([^()\n]+:\d+(?::\d+)?\)\s*$",
|
|
61
|
+
re.MULTILINE,
|
|
62
|
+
),
|
|
63
|
+
# JVM — "\tat com.example.Class.method(File.java:42)"
|
|
64
|
+
re.compile(r"^\s+at\s+\S+\.\S+\([^()\n]+:\d+\)\s*$", re.MULTILINE),
|
|
65
|
+
# Ruby — "/app/lib/foo.rb:42:in `bar'" or "\tfrom ...rb:8:in '<main>'"
|
|
66
|
+
re.compile(
|
|
67
|
+
r"^\s*(?:from\s+)?[^:\n]+\.rb:\d+:in\s+[`'][^`'\n]+[`']",
|
|
68
|
+
re.MULTILINE,
|
|
69
|
+
),
|
|
70
|
+
# .NET — " at Namespace.Type.Method(...) in File.cs:line 42"
|
|
71
|
+
re.compile(
|
|
72
|
+
r"^\s+at\s+\S+\.\S+\([^()\n]*\)\s+in\s+[^:\n]+\.cs:line\s+\d+\s*$",
|
|
73
|
+
re.MULTILINE,
|
|
74
|
+
),
|
|
75
|
+
# PHP — "#0 /app/src/Foo.php(42): Class->method(...)"
|
|
76
|
+
re.compile(r"^#\d+\s+[^()\n]+\.php\(\d+\):\s+\S+", re.MULTILINE),
|
|
77
|
+
# C/C++ — addr2line / backtrace lines look like "#0 0x... in fn at file:42"
|
|
78
|
+
re.compile(r"^#\d+\s+0x[0-9a-fA-F]+\s+in\s+\S+", re.MULTILINE),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def detect_stacktrace(query: str) -> bool:
|
|
83
|
+
"""Return True if the query embeds a recognisable runtime stack trace."""
|
|
84
|
+
if not query:
|
|
85
|
+
return False
|
|
86
|
+
return any(p.search(query) for p in _STACKTRACE_PATTERNS)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
_LANGUAGE_ALIASES: Dict[str, str] = agent_language_aliases()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def normalize_language(raw: Optional[str]) -> Optional[str]:
|
|
93
|
+
"""Map a dataset / repo-meta language string to a canonical key.
|
|
94
|
+
|
|
95
|
+
Returns ``None`` for unknown or empty inputs so callers can branch on
|
|
96
|
+
"no language signal" without sentinel strings.
|
|
97
|
+
"""
|
|
98
|
+
if not raw:
|
|
99
|
+
return None
|
|
100
|
+
return normalize_agent_language(raw)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass(frozen=True, slots=True)
|
|
104
|
+
class Scenario:
|
|
105
|
+
"""A (query, repo) bucket used as a compile-table lookup key.
|
|
106
|
+
|
|
107
|
+
Two-dimensional per RFC v2 — ``query_length`` and ``query_concreteness``
|
|
108
|
+
from v1 were dropped to keep the eval cells statistically meaningful.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
language: Optional[str]
|
|
112
|
+
has_stacktrace: bool
|
|
113
|
+
|
|
114
|
+
def key(self) -> str:
|
|
115
|
+
"""Stable string key for ``compile_table.json`` lookup."""
|
|
116
|
+
lang = self.language or "unknown"
|
|
117
|
+
flag = "stacktrace" if self.has_stacktrace else "no_stacktrace"
|
|
118
|
+
return f"{lang}:{flag}"
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def from_key(cls, key: str) -> "Scenario":
|
|
122
|
+
lang, flag = key.split(":", 1)
|
|
123
|
+
return cls(
|
|
124
|
+
language=None if lang == "unknown" else lang,
|
|
125
|
+
has_stacktrace=(flag == "stacktrace"),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def classify(query: str, session_ctx: Optional[SessionContext]) -> Scenario:
|
|
130
|
+
"""Compute the scenario for a single (query, repo) pair."""
|
|
131
|
+
lang: Optional[str] = None
|
|
132
|
+
if session_ctx is not None:
|
|
133
|
+
lang = normalize_language(session_ctx.primary_language)
|
|
134
|
+
return Scenario(language=lang, has_stacktrace=detect_stacktrace(query))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
CompileTable = Mapping[str, Iterable[str]]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def load_compile_table(path: Union[str, Path]) -> Dict[str, FrozenSet[str]]:
|
|
141
|
+
"""Load a ``compile_table`` file as a ``{scenario_key: frozenset}`` map.
|
|
142
|
+
|
|
143
|
+
Supports JSON (``.json``) and YAML (``.yaml`` / ``.yml``). The on-disk
|
|
144
|
+
format is a mapping whose keys are the strings returned by
|
|
145
|
+
:meth:`Scenario.key` and whose values are lists of skill IDs.
|
|
146
|
+
"""
|
|
147
|
+
p = Path(path)
|
|
148
|
+
suffix = p.suffix.lower()
|
|
149
|
+
with p.open("r", encoding="utf-8") as f:
|
|
150
|
+
if suffix in {".yaml", ".yml"}:
|
|
151
|
+
import yaml # local import — PyYAML is already a project dep
|
|
152
|
+
|
|
153
|
+
raw = yaml.safe_load(f)
|
|
154
|
+
elif suffix == ".json":
|
|
155
|
+
raw = json.load(f)
|
|
156
|
+
else:
|
|
157
|
+
raise ValueError(
|
|
158
|
+
f"compile_table at {p}: unsupported extension {suffix!r}; "
|
|
159
|
+
"use .json, .yaml, or .yml"
|
|
160
|
+
)
|
|
161
|
+
if not isinstance(raw, dict):
|
|
162
|
+
raise ValueError(
|
|
163
|
+
f"compile_table at {p} must be a mapping, got {type(raw).__name__}"
|
|
164
|
+
)
|
|
165
|
+
out: Dict[str, FrozenSet[str]] = {}
|
|
166
|
+
for k, v in raw.items():
|
|
167
|
+
if not isinstance(v, (list, tuple)):
|
|
168
|
+
raise ValueError(
|
|
169
|
+
f"compile_table[{k!r}] must be a list of skill IDs, "
|
|
170
|
+
f"got {type(v).__name__}"
|
|
171
|
+
)
|
|
172
|
+
out[k] = frozenset(str(s) for s in v)
|
|
173
|
+
return out
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def agent_compile(
|
|
177
|
+
query: str,
|
|
178
|
+
session_ctx: Optional[SessionContext],
|
|
179
|
+
table: Optional[CompileTable] = None,
|
|
180
|
+
) -> Optional[FrozenSet[str]]:
|
|
181
|
+
"""Resolve which skills the agent should be allowed to invoke.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
query: The incoming user query / problem statement.
|
|
185
|
+
session_ctx: Repo-side context (language, repo size, ...). May be ``None``.
|
|
186
|
+
table: Mapping from scenario key to skill-ID iterable. ``None`` or empty
|
|
187
|
+
means "no restriction" — caller should expose the full registry.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
A ``frozenset`` of skill IDs to allow, or ``None`` to signal "no
|
|
191
|
+
restriction" (caller falls back to its default, typically A6 = full
|
|
192
|
+
registry). This matches ``AgentRunner.allow_skills`` semantics where
|
|
193
|
+
``None`` means "no filter".
|
|
194
|
+
"""
|
|
195
|
+
if not table:
|
|
196
|
+
return None
|
|
197
|
+
scenario = classify(query, session_ctx)
|
|
198
|
+
key = scenario.key()
|
|
199
|
+
if key in table:
|
|
200
|
+
return frozenset(table[key])
|
|
201
|
+
logger.warning(
|
|
202
|
+
"agent_compile: scenario %r not in compile_table (size=%d); "
|
|
203
|
+
"falling back to full registry",
|
|
204
|
+
key,
|
|
205
|
+
len(table),
|
|
206
|
+
)
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
__all__ = [
|
|
211
|
+
"Scenario",
|
|
212
|
+
"CompileTable",
|
|
213
|
+
"SUPPORTED_LANGUAGES",
|
|
214
|
+
"classify",
|
|
215
|
+
"detect_stacktrace",
|
|
216
|
+
"normalize_language",
|
|
217
|
+
"load_compile_table",
|
|
218
|
+
"agent_compile",
|
|
219
|
+
]
|