skylos 4.50.0__py3-none-win_amd64.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 (717) hide show
  1. skylos/__init__.py +39 -0
  2. skylos/adapters/__init__.py +8 -0
  3. skylos/adapters/base.py +11 -0
  4. skylos/adapters/litellm_adapter.py +528 -0
  5. skylos/agents/__init__.py +1 -0
  6. skylos/agents/center.py +1326 -0
  7. skylos/agents/evaluation/__init__.py +35 -0
  8. skylos/agents/evaluation/_assertion_helpers.py +41 -0
  9. skylos/agents/evaluation/_loader_support.py +246 -0
  10. skylos/agents/evaluation/_openai_response.py +297 -0
  11. skylos/agents/evaluation/_openai_transport.py +254 -0
  12. skylos/agents/evaluation/_runner_evidence.py +284 -0
  13. skylos/agents/evaluation/_tool_evaluator.py +324 -0
  14. skylos/agents/evaluation/evaluator.py +316 -0
  15. skylos/agents/evaluation/evidence.py +170 -0
  16. skylos/agents/evaluation/loader.py +548 -0
  17. skylos/agents/evaluation/observation_loader.py +238 -0
  18. skylos/agents/evaluation/openai_chat.py +516 -0
  19. skylos/agents/evaluation/runner.py +680 -0
  20. skylos/agents/evaluation/schema.py +222 -0
  21. skylos/agents/payload.py +242 -0
  22. skylos/agents/service.py +585 -0
  23. skylos/agents/triage_learner.py +326 -0
  24. skylos/analysis/__init__.py +1 -0
  25. skylos/analysis/architecture.py +599 -0
  26. skylos/analysis/architecture_findings.py +224 -0
  27. skylos/analysis/architecture_layers.py +206 -0
  28. skylos/analysis/architecture_support.py +73 -0
  29. skylos/analysis/ast_cache.py +238 -0
  30. skylos/analysis/ast_mask.py +161 -0
  31. skylos/analysis/attribute_refs.py +286 -0
  32. skylos/analysis/circular_deps.py +475 -0
  33. skylos/analysis/control_flow.py +218 -0
  34. skylos/analysis/documented_conventions.py +405 -0
  35. skylos/analysis/errors.py +71 -0
  36. skylos/analysis/file_processing.py +565 -0
  37. skylos/analysis/file_worker.py +584 -0
  38. skylos/analysis/finding_filter.py +68 -0
  39. skylos/analysis/implicit_refs.py +172 -0
  40. skylos/analysis/known_patterns.py +671 -0
  41. skylos/analysis/module_reachability.py +249 -0
  42. skylos/analysis/penalties.py +1616 -0
  43. skylos/analysis/pyproject_entrypoints.py +60 -0
  44. skylos/analysis/typescript_architecture.py +217 -0
  45. skylos/analyzer.py +6217 -0
  46. skylos/api/__init__.py +3356 -0
  47. skylos/api/_ai_detection.py +177 -0
  48. skylos/api/_artifacts.py +434 -0
  49. skylos/api/_contract_check.py +104 -0
  50. skylos/api/_findings.py +289 -0
  51. skylos/api/_payloads.py +307 -0
  52. skylos/api/_pending_uploads.py +599 -0
  53. skylos/api/_scan_coverage.py +277 -0
  54. skylos/api/_snippets.py +45 -0
  55. skylos/api/_source_revision.py +171 -0
  56. skylos/api/_upload_contract.py +182 -0
  57. skylos/api/_upload_paths.py +243 -0
  58. skylos/api/_upload_preflight.py +227 -0
  59. skylos/api/_upload_transport.py +563 -0
  60. skylos/api/_urls.py +181 -0
  61. skylos/api/upload_contract/v1.json +173 -0
  62. skylos/audit/__init__.py +1 -0
  63. skylos/audit/candidates.py +967 -0
  64. skylos/audit/ci.py +204 -0
  65. skylos/audit/export.py +1243 -0
  66. skylos/audit/freshness.py +448 -0
  67. skylos/audit/investigator_tools/__init__.py +48 -0
  68. skylos/audit/investigator_tools/catalog.py +181 -0
  69. skylos/audit/investigator_tools/models.py +106 -0
  70. skylos/audit/investigator_tools/operations.py +278 -0
  71. skylos/audit/investigator_tools/rendering.py +53 -0
  72. skylos/audit/investigator_tools/safety.py +69 -0
  73. skylos/audit/investigator_tools/session.py +262 -0
  74. skylos/audit/investigator_tools/validation.py +50 -0
  75. skylos/audit/polyglot.py +428 -0
  76. skylos/audit/processor.py +1841 -0
  77. skylos/audit/redaction.py +83 -0
  78. skylos/audit/revalidation/__init__.py +1 -0
  79. skylos/audit/revalidation/constants.py +74 -0
  80. skylos/audit/revalidation/evidence.py +357 -0
  81. skylos/audit/revalidation/policy.py +304 -0
  82. skylos/audit/revalidation/verifiers.py +442 -0
  83. skylos/audit/revalidator.py +303 -0
  84. skylos/audit/store.py +868 -0
  85. skylos/audit/types.py +522 -0
  86. skylos/benchmarks/__init__.py +1 -0
  87. skylos/benchmarks/_jev_dead_code_dataset.py +658 -0
  88. skylos/benchmarks/_jev_dead_code_golden.py +168 -0
  89. skylos/benchmarks/_jev_dead_code_report.py +355 -0
  90. skylos/benchmarks/_jev_dead_code_types.py +33 -0
  91. skylos/benchmarks/agent_behavior.py +117 -0
  92. skylos/benchmarks/agent_review.py +958 -0
  93. skylos/benchmarks/ai_code_defects.py +1489 -0
  94. skylos/benchmarks/corpus_ci.py +227 -0
  95. skylos/benchmarks/dead_code.py +1084 -0
  96. skylos/benchmarks/deep_audit_logic.py +1144 -0
  97. skylos/benchmarks/demo_deadcode.py +171 -0
  98. skylos/benchmarks/framework_corpus.py +409 -0
  99. skylos/benchmarks/framework_corpus_schema.py +195 -0
  100. skylos/benchmarks/jev_compare.py +577 -0
  101. skylos/benchmarks/jev_dead_code.py +488 -0
  102. skylos/benchmarks/quality.py +527 -0
  103. skylos/benchmarks/security.py +764 -0
  104. skylos/benchmarks/verify_benchmark.py +116 -0
  105. skylos/benchmarks/verify_benchmark_eval.py +310 -0
  106. skylos/benchmarks/verify_benchmark_report.py +208 -0
  107. skylos/benchmarks/verify_benchmark_runner.py +273 -0
  108. skylos/cicd/__init__.py +1 -0
  109. skylos/cicd/approval.py +924 -0
  110. skylos/cicd/approval_dependencies.py +1378 -0
  111. skylos/cicd/approval_github.py +242 -0
  112. skylos/cicd/evidence.py +994 -0
  113. skylos/cicd/init_setup.py +331 -0
  114. skylos/cicd/merge_group.py +478 -0
  115. skylos/cicd/policy.py +141 -0
  116. skylos/cicd/review.py +1859 -0
  117. skylos/cicd/risk_passport.py +363 -0
  118. skylos/cicd/scope_receipt.py +167 -0
  119. skylos/cicd/workflow.py +955 -0
  120. skylos/cli.py +5997 -0
  121. skylos/cli_core/__init__.py +0 -0
  122. skylos/cli_core/dispatch.py +141 -0
  123. skylos/cli_core/main_parser.py +523 -0
  124. skylos/cloud/__init__.py +1 -0
  125. skylos/cloud/credentials.py +72 -0
  126. skylos/cloud/gitlab.py +352 -0
  127. skylos/cloud/login.py +488 -0
  128. skylos/cloud/plan_names.py +20 -0
  129. skylos/cloud/project_context.py +54 -0
  130. skylos/cloud/shadow_upload.py +524 -0
  131. skylos/cloud/sync.py +1215 -0
  132. skylos/cloud/sync_setup.py +331 -0
  133. skylos/cloud/sync_state.py +294 -0
  134. skylos/cloud/upload_manifest.py +138 -0
  135. skylos/cloud/windows_sync.py +447 -0
  136. skylos/commands/__init__.py +0 -0
  137. skylos/commands/agent_replay_cmd.py +270 -0
  138. skylos/commands/agent_standards_policy.py +146 -0
  139. skylos/commands/agent_test_cmd.py +580 -0
  140. skylos/commands/agent_verify_cmd.py +765 -0
  141. skylos/commands/badge_cmd.py +42 -0
  142. skylos/commands/baseline_cmd.py +159 -0
  143. skylos/commands/cache_cmd.py +127 -0
  144. skylos/commands/check_standards_cmd.py +238 -0
  145. skylos/commands/cicd_cmd.py +655 -0
  146. skylos/commands/clean_cmd.py +448 -0
  147. skylos/commands/compare_cmd.py +675 -0
  148. skylos/commands/contract_cmd.py +256 -0
  149. skylos/commands/credits_cmd.py +81 -0
  150. skylos/commands/debt_cmd.py +452 -0
  151. skylos/commands/defend_cmd.py +862 -0
  152. skylos/commands/discover_cmd.py +86 -0
  153. skylos/commands/doctor_cmd.py +408 -0
  154. skylos/commands/doctor_hooks.py +513 -0
  155. skylos/commands/done_cmd.py +273 -0
  156. skylos/commands/feedback_cmd.py +173 -0
  157. skylos/commands/hook_attribution.py +481 -0
  158. skylos/commands/hook_cmd.py +2656 -0
  159. skylos/commands/hook_git_bypass.py +606 -0
  160. skylos/commands/hook_install_parse.py +1654 -0
  161. skylos/commands/hook_install_policy.py +97 -0
  162. skylos/commands/hook_policy.py +488 -0
  163. skylos/commands/hook_registry_context.py +354 -0
  164. skylos/commands/hook_shell_commands.py +303 -0
  165. skylos/commands/hook_shell_filters.py +743 -0
  166. skylos/commands/hook_shell_grep.py +323 -0
  167. skylos/commands/hook_shell_lex.py +306 -0
  168. skylos/commands/hook_shell_reads.py +740 -0
  169. skylos/commands/image_cmd.py +389 -0
  170. skylos/commands/ingest_cmd.py +99 -0
  171. skylos/commands/init_cmd.py +121 -0
  172. skylos/commands/install_hooks_cmd.py +572 -0
  173. skylos/commands/install_standards_cmd.py +296 -0
  174. skylos/commands/key_cmd.py +222 -0
  175. skylos/commands/lint_cmd.py +48 -0
  176. skylos/commands/login_cmd.py +11 -0
  177. skylos/commands/mcp_cmd.py +42 -0
  178. skylos/commands/preflight_cmd.py +428 -0
  179. skylos/commands/project_cmd.py +5 -0
  180. skylos/commands/provenance_cmd.py +184 -0
  181. skylos/commands/review_cmd.py +606 -0
  182. skylos/commands/risk_review_cmd.py +569 -0
  183. skylos/commands/rules_cmd.py +517 -0
  184. skylos/commands/sbom_cmd.py +115 -0
  185. skylos/commands/scan_cmd.py +1995 -0
  186. skylos/commands/sonar_cmd.py +80 -0
  187. skylos/commands/suite_cmd.py +563 -0
  188. skylos/commands/sync_cmd.py +5 -0
  189. skylos/commands/trivy_image_cmd.py +219 -0
  190. skylos/commands/upload_cmd.py +170 -0
  191. skylos/commands/verify_cmd.py +413 -0
  192. skylos/commands/verify_verdict_cmd.py +544 -0
  193. skylos/commands/warm_cache_cmd.py +65 -0
  194. skylos/commands/whitelist_cmd.py +113 -0
  195. skylos/commands/whoami_cmd.py +25 -0
  196. skylos/config.py +1120 -0
  197. skylos/constants.py +230 -0
  198. skylos/contracts/__init__.py +49 -0
  199. skylos/contracts/loader.py +363 -0
  200. skylos/contracts/metadata.py +211 -0
  201. skylos/contracts/routes.py +424 -0
  202. skylos/contracts/schema.py +64 -0
  203. skylos/core/__init__.py +1 -0
  204. skylos/core/api_symbol_truth.py +390 -0
  205. skylos/core/baseline.py +198 -0
  206. skylos/core/baseline_source.py +162 -0
  207. skylos/core/ci_env.py +131 -0
  208. skylos/core/cli_shared.py +299 -0
  209. skylos/core/contribution_events.py +157 -0
  210. skylos/core/contribution_settings.py +61 -0
  211. skylos/core/evidence_contract.py +587 -0
  212. skylos/core/fast.py +28 -0
  213. skylos/core/fast_paths.py +81 -0
  214. skylos/core/file_discovery.py +494 -0
  215. skylos/core/gate_incomplete.py +720 -0
  216. skylos/core/gate_outcome.py +194 -0
  217. skylos/core/gatekeeper.py +1331 -0
  218. skylos/core/generated_files.py +389 -0
  219. skylos/core/git_context.py +243 -0
  220. skylos/core/git_safety.py +52 -0
  221. skylos/core/go_api_surface.py +576 -0
  222. skylos/core/go_module_manifest.py +133 -0
  223. skylos/core/grep_cache.py +255 -0
  224. skylos/core/grep_search_state.py +78 -0
  225. skylos/core/grep_verify.py +936 -0
  226. skylos/core/grep_verify_common.py +3018 -0
  227. skylos/core/grep_verify_language_strategies.py +404 -0
  228. skylos/core/grep_verify_parallel.py +90 -0
  229. skylos/core/grep_verify_python_strategy.py +527 -0
  230. skylos/core/grep_verify_strategies.py +131 -0
  231. skylos/core/java_api_surface.py +508 -0
  232. skylos/core/js_api_surface.py +502 -0
  233. skylos/core/js_api_surface_exports.py +685 -0
  234. skylos/core/js_api_surface_members.py +485 -0
  235. skylos/core/js_api_surface_utils.py +207 -0
  236. skylos/core/js_ast.py +109 -0
  237. skylos/core/linter.py +33 -0
  238. skylos/core/pr_impact.py +224 -0
  239. skylos/core/python_api_surface.py +704 -0
  240. skylos/core/python_distributions.py +311 -0
  241. skylos/core/python_requirements.py +671 -0
  242. skylos/core/reference_index.py +213 -0
  243. skylos/core/reference_index_store.py +335 -0
  244. skylos/core/report_context.py +473 -0
  245. skylos/core/result_cache.py +562 -0
  246. skylos/core/review_context.py +1215 -0
  247. skylos/core/review_decisions.py +3892 -0
  248. skylos/core/safe_cache_io.py +776 -0
  249. skylos/core/sca_baseline.py +279 -0
  250. skylos/core/sca_coverage.py +218 -0
  251. skylos/core/suite.py +408 -0
  252. skylos/core/test_paths.py +201 -0
  253. skylos/core/tracer.py +215 -0
  254. skylos/core/verification_coverage.py +153 -0
  255. skylos/core/verification_registry.py +476 -0
  256. skylos/core/verify_change_schema.py +819 -0
  257. skylos/deadcode/__init__.py +1 -0
  258. skylos/deadcode/_reachability_bindings.py +228 -0
  259. skylos/deadcode/_reachability_graph.py +249 -0
  260. skylos/deadcode/_reachability_receivers.py +188 -0
  261. skylos/deadcode/_reachability_scopes.py +62 -0
  262. skylos/deadcode/_reachability_visitor.py +648 -0
  263. skylos/deadcode/browser_refs.py +747 -0
  264. skylos/deadcode/collect.py +19 -0
  265. skylos/deadcode/confidence.py +228 -0
  266. skylos/deadcode/config_entrypoints.py +312 -0
  267. skylos/deadcode/django_framework_liveness.py +425 -0
  268. skylos/deadcode/django_template_liveness.py +269 -0
  269. skylos/deadcode/evidence.py +934 -0
  270. skylos/deadcode/external_protocols.py +625 -0
  271. skylos/deadcode/finding_evidence.py +142 -0
  272. skylos/deadcode/framework_liveness.py +452 -0
  273. skylos/deadcode/java_fxml_refs.py +314 -0
  274. skylos/deadcode/liveness.py +761 -0
  275. skylos/deadcode/plugin_registry.py +606 -0
  276. skylos/deadcode/python_ast.py +35 -0
  277. skylos/deadcode/reachability.py +431 -0
  278. skylos/deadcode/review_proof.py +345 -0
  279. skylos/deadcode/signature_contracts.py +556 -0
  280. skylos/deadcode/web_framework_ast.py +69 -0
  281. skylos/deadcode/web_framework_liveness.py +684 -0
  282. skylos/debt/__init__.py +73 -0
  283. skylos/debt/advisor.py +291 -0
  284. skylos/debt/baseline.py +467 -0
  285. skylos/debt/engine.py +350 -0
  286. skylos/debt/policy.py +173 -0
  287. skylos/debt/report.py +389 -0
  288. skylos/debt/result.py +137 -0
  289. skylos/debt/scoring.py +300 -0
  290. skylos/defend/__init__.py +38 -0
  291. skylos/defend/attestation.py +240 -0
  292. skylos/defend/engine.py +83 -0
  293. skylos/defend/frameworks.py +439 -0
  294. skylos/defend/owasp.py +318 -0
  295. skylos/defend/plugin.py +64 -0
  296. skylos/defend/plugins/__init__.py +39 -0
  297. skylos/defend/plugins/cost_controls.py +39 -0
  298. skylos/defend/plugins/input_length_limit.py +38 -0
  299. skylos/defend/plugins/logging_present.py +35 -0
  300. skylos/defend/plugins/model_pinned.py +45 -0
  301. skylos/defend/plugins/no_dangerous_sink.py +38 -0
  302. skylos/defend/plugins/output_pii_filter.py +38 -0
  303. skylos/defend/plugins/output_validation.py +89 -0
  304. skylos/defend/plugins/prompt_delimiter.py +38 -0
  305. skylos/defend/plugins/rag_context_isolation.py +38 -0
  306. skylos/defend/plugins/rate_limiting.py +39 -0
  307. skylos/defend/plugins/tool_schema_present.py +41 -0
  308. skylos/defend/plugins/tool_scope.py +45 -0
  309. skylos/defend/plugins/untrusted_input_to_prompt.py +43 -0
  310. skylos/defend/policy.py +149 -0
  311. skylos/defend/report.py +670 -0
  312. skylos/defend/result.py +68 -0
  313. skylos/defend/scoring.py +125 -0
  314. skylos/discover/__init__.py +15 -0
  315. skylos/discover/detector.py +1600 -0
  316. skylos/discover/detector_typescript.py +633 -0
  317. skylos/discover/graph.py +97 -0
  318. skylos/discover/integration.py +77 -0
  319. skylos/discover/report.py +66 -0
  320. skylos/discover/semantics/__init__.py +5 -0
  321. skylos/discover/semantics/python_output_flow.py +1029 -0
  322. skylos/discover/semantics/vocabulary.py +38 -0
  323. skylos/discover/taint.py +209 -0
  324. skylos/done/__init__.py +10 -0
  325. skylos/done/answer_sites.py +2402 -0
  326. skylos/done/base.py +525 -0
  327. skylos/done/checks.py +1649 -0
  328. skylos/done/ci_checks.py +1262 -0
  329. skylos/done/config.py +370 -0
  330. skylos/done/engine.py +139 -0
  331. skylos/done/expected_answers.py +1231 -0
  332. skylos/done/feature_removal.py +600 -0
  333. skylos/done/inventory.py +1483 -0
  334. skylos/done/js_inventory.py +2408 -0
  335. skylos/done/js_test_config.py +1800 -0
  336. skylos/done/lint_config.py +2107 -0
  337. skylos/done/mutation.py +779 -0
  338. skylos/done/orphans.py +1538 -0
  339. skylos/done/preexisting.py +1498 -0
  340. skylos/done/pytest_probe.py +410 -0
  341. skylos/done/receipt.py +971 -0
  342. skylos/done/runner.py +1085 -0
  343. skylos/done/security_controls.py +126 -0
  344. skylos/done/session.py +698 -0
  345. skylos/done/special_cases.py +931 -0
  346. skylos/done/suppressions.py +1281 -0
  347. skylos/done/test_config.py +2263 -0
  348. skylos/engines/__init__.py +0 -0
  349. skylos/engines/go/skylos-go.exe +0 -0
  350. skylos/engines/go_contract.py +47 -0
  351. skylos/engines/go_runner.py +202 -0
  352. skylos/entry.py +156 -0
  353. skylos/integrations/__init__.py +1 -0
  354. skylos/integrations/ingest.py +344 -0
  355. skylos/integrations/shadow.py +2239 -0
  356. skylos/integrations/sonar.py +155 -0
  357. skylos/integrations/trivy_image.py +566 -0
  358. skylos/llm/__init__.py +0 -0
  359. skylos/llm/_grounding.py +466 -0
  360. skylos/llm/agents.py +808 -0
  361. skylos/llm/analyzer.py +713 -0
  362. skylos/llm/cleanup_orchestrator.py +572 -0
  363. skylos/llm/cleanup_standards.md +60 -0
  364. skylos/llm/completion_diagnostics.py +54 -0
  365. skylos/llm/context.py +772 -0
  366. skylos/llm/dead_code_verifier.py +123 -0
  367. skylos/llm/executor.py +360 -0
  368. skylos/llm/feedback.py +186 -0
  369. skylos/llm/finding_evidence.py +343 -0
  370. skylos/llm/finding_verification.py +270 -0
  371. skylos/llm/graph.py +606 -0
  372. skylos/llm/harness/__init__.py +73 -0
  373. skylos/llm/harness/ai_defect_challenge.py +343 -0
  374. skylos/llm/harness/ai_defect_challenge_decisions.py +270 -0
  375. skylos/llm/harness/ai_defect_challenge_models.py +98 -0
  376. skylos/llm/harness/ai_defect_challenge_probes.py +138 -0
  377. skylos/llm/harness/ai_defect_challenge_prompt.py +62 -0
  378. skylos/llm/harness/ai_defect_challenge_proof.py +205 -0
  379. skylos/llm/harness/guards.py +42 -0
  380. skylos/llm/harness/replay.py +1043 -0
  381. skylos/llm/harness/runner.py +417 -0
  382. skylos/llm/harness/tools.py +121 -0
  383. skylos/llm/harness/trace.py +218 -0
  384. skylos/llm/harness/types.py +253 -0
  385. skylos/llm/harness/verification.py +109 -0
  386. skylos/llm/investigator/__init__.py +53 -0
  387. skylos/llm/investigator/actions.py +155 -0
  388. skylos/llm/investigator/adapter.py +103 -0
  389. skylos/llm/investigator/evidence.py +264 -0
  390. skylos/llm/investigator/findings.py +343 -0
  391. skylos/llm/investigator/models.py +186 -0
  392. skylos/llm/investigator/orchestrator.py +564 -0
  393. skylos/llm/investigator/prompts.py +95 -0
  394. skylos/llm/investigator/protocol.py +363 -0
  395. skylos/llm/investigator/repository_tools.py +130 -0
  396. skylos/llm/investigator/reviewer_packs.py +385 -0
  397. skylos/llm/investigator/source_bounds.py +12 -0
  398. skylos/llm/jev_triage.py +216 -0
  399. skylos/llm/liveness.py +323 -0
  400. skylos/llm/merger.py +236 -0
  401. skylos/llm/orchestrator.py +371 -0
  402. skylos/llm/planner.py +176 -0
  403. skylos/llm/prompts.py +569 -0
  404. skylos/llm/repo_activation.py +472 -0
  405. skylos/llm/review/__init__.py +5 -0
  406. skylos/llm/review/refuters.py +423 -0
  407. skylos/llm/review/routing.py +330 -0
  408. skylos/llm/review/static_findings.py +491 -0
  409. skylos/llm/runtime.py +96 -0
  410. skylos/llm/schemas.py +469 -0
  411. skylos/llm/security_taskflow.py +1062 -0
  412. skylos/llm/security_verifier.py +682 -0
  413. skylos/llm/threat_trace.py +642 -0
  414. skylos/llm/ui.py +501 -0
  415. skylos/llm/validator.py +413 -0
  416. skylos/llm/verification/__init__.py +1 -0
  417. skylos/llm/verification/candidate_selection.py +218 -0
  418. skylos/llm/verification/completion_phases.py +422 -0
  419. skylos/llm/verification/entry_points.py +496 -0
  420. skylos/llm/verification/jev_precheck.py +219 -0
  421. skylos/llm/verification/llm.py +417 -0
  422. skylos/llm/verification/phases.py +154 -0
  423. skylos/llm/verification/runtime.py +47 -0
  424. skylos/llm/verification/suppression_audit.py +173 -0
  425. skylos/llm/verification/survivors.py +491 -0
  426. skylos/llm/verification/types.py +74 -0
  427. skylos/llm/verification/verify_findings.py +271 -0
  428. skylos/llm/verify_orchestrator.py +2930 -0
  429. skylos/pipeline.py +1254 -0
  430. skylos/plugins/__init__.py +1 -0
  431. skylos/plugins/pytest_unused_fixtures.py +188 -0
  432. skylos/preflight/__init__.py +315 -0
  433. skylos/preflight/evaluator.py +714 -0
  434. skylos/preflight/inspector.py +1636 -0
  435. skylos/preflight/models.py +305 -0
  436. skylos/preflight/profile.py +58 -0
  437. skylos/remediation/__init__.py +1 -0
  438. skylos/remediation/codemods.py +389 -0
  439. skylos/remediation/fixgen.py +593 -0
  440. skylos/remediation/regression_tests.py +250 -0
  441. skylos/remediation/safety.py +35 -0
  442. skylos/reporting/__init__.py +1 -0
  443. skylos/reporting/architecture_result.py +412 -0
  444. skylos/reporting/assessment.py +373 -0
  445. skylos/reporting/assessment_display.py +286 -0
  446. skylos/reporting/attribution_evidence.py +591 -0
  447. skylos/reporting/container_sarif.py +111 -0
  448. skylos/reporting/dead_code_result.py +337 -0
  449. skylos/reporting/finding_categories.py +23 -0
  450. skylos/reporting/finding_types.py +176 -0
  451. skylos/reporting/github_annotations.py +162 -0
  452. skylos/reporting/gitlab.py +469 -0
  453. skylos/reporting/grader.py +356 -0
  454. skylos/reporting/llm_report.py +304 -0
  455. skylos/reporting/provenance.py +1180 -0
  456. skylos/reporting/report_scope.py +126 -0
  457. skylos/reporting/result_builder.py +598 -0
  458. skylos/reporting/rollups.py +162 -0
  459. skylos/reporting/sarif.py +663 -0
  460. skylos/reporting/sbom.py +331 -0
  461. skylos/reporting/sca_summary.py +152 -0
  462. skylos/reporting/spdx.py +292 -0
  463. skylos/rules/__init__.py +0 -0
  464. skylos/rules/ai_defect/__init__.py +47 -0
  465. skylos/rules/ai_defect/api_signature_hallucination.py +932 -0
  466. skylos/rules/ai_defect/api_surface_drift.py +144 -0
  467. skylos/rules/ai_defect/assertion_weakening.py +1155 -0
  468. skylos/rules/ai_defect/ci_permission_expansion.py +612 -0
  469. skylos/rules/ai_defect/dependency_bump_scan.py +273 -0
  470. skylos/rules/ai_defect/dependency_hallucination.py +3655 -0
  471. skylos/rules/ai_defect/dependency_truth.py +108 -0
  472. skylos/rules/ai_defect/dependency_version_bump.py +798 -0
  473. skylos/rules/ai_defect/diff_dependencies.py +956 -0
  474. skylos/rules/ai_defect/go_api_hallucination.py +479 -0
  475. skylos/rules/ai_defect/guardrails/__init__.py +41 -0
  476. skylos/rules/ai_defect/guardrails/core.py +297 -0
  477. skylos/rules/ai_defect/guardrails/markers.py +615 -0
  478. skylos/rules/ai_defect/guardrails/reviewer.py +601 -0
  479. skylos/rules/ai_defect/guardrails/scan.py +251 -0
  480. skylos/rules/ai_defect/install_command.py +598 -0
  481. skylos/rules/ai_defect/installed_modules_cache.py +84 -0
  482. skylos/rules/ai_defect/java_api_hallucination.py +501 -0
  483. skylos/rules/ai_defect/java_api_hallucination_reporting.py +226 -0
  484. skylos/rules/ai_defect/java_api_hallucination_resolution.py +209 -0
  485. skylos/rules/ai_defect/js_api_hallucination.py +524 -0
  486. skylos/rules/ai_defect/js_api_namespace_references.py +150 -0
  487. skylos/rules/ai_defect/js_api_reference_model.py +90 -0
  488. skylos/rules/ai_defect/js_api_references.py +401 -0
  489. skylos/rules/ai_defect/manifest_dependency_hallucination.py +2262 -0
  490. skylos/rules/ai_defect/module_facts_index.py +249 -0
  491. skylos/rules/ai_defect/phantom_call.py +92 -0
  492. skylos/rules/ai_defect/phantom_decorator.py +98 -0
  493. skylos/rules/ai_defect/phantom_refs.py +2616 -0
  494. skylos/rules/ai_defect/pipreqs_import_mapping.txt +1164 -0
  495. skylos/rules/ai_defect/pypi_wheel_modules.py +544 -0
  496. skylos/rules/ai_defect/python_api_hallucination.py +665 -0
  497. skylos/rules/ai_defect/test_impact.py +342 -0
  498. skylos/rules/base.py +23 -0
  499. skylos/rules/catalog.py +1492 -0
  500. skylos/rules/compliance.py +185 -0
  501. skylos/rules/config/__init__.py +3 -0
  502. skylos/rules/config/cicd/__init__.py +4 -0
  503. skylos/rules/config/cicd/ai_agent_expressions.py +661 -0
  504. skylos/rules/config/cicd/ai_agent_versions.py +347 -0
  505. skylos/rules/config/cicd/ai_agents.py +1838 -0
  506. skylos/rules/config/cicd/github_actions.py +2518 -0
  507. skylos/rules/config/cicd/gitlab_ci.py +1062 -0
  508. skylos/rules/config/cicd/runner_labels.py +202 -0
  509. skylos/rules/config/cicd/yaml_source.py +267 -0
  510. skylos/rules/config/container/__init__.py +3 -0
  511. skylos/rules/config/container/dockerfile.py +438 -0
  512. skylos/rules/config/deployment/__init__.py +3 -0
  513. skylos/rules/config/deployment/exposure.py +2752 -0
  514. skylos/rules/config/edge/__init__.py +12 -0
  515. skylos/rules/config/edge/docker_compose.py +538 -0
  516. skylos/rules/config/edge/systemd.py +562 -0
  517. skylos/rules/config/findings.py +38 -0
  518. skylos/rules/config/gpu/__init__.py +3 -0
  519. skylos/rules/config/gpu/compatibility.py +2299 -0
  520. skylos/rules/config/registry.py +147 -0
  521. skylos/rules/custom.py +388 -0
  522. skylos/rules/danger/__init__.py +0 -0
  523. skylos/rules/danger/calls.py +641 -0
  524. skylos/rules/danger/danger.py +649 -0
  525. skylos/rules/danger/danger_access/__init__.py +0 -0
  526. skylos/rules/danger/danger_access/access_flow.py +67 -0
  527. skylos/rules/danger/danger_agent/__init__.py +2 -0
  528. skylos/rules/danger/danger_agent/tool_privilege.py +365 -0
  529. skylos/rules/danger/danger_cmd/__init__.py +0 -0
  530. skylos/rules/danger/danger_cmd/cmd_flow.py +90 -0
  531. skylos/rules/danger/danger_cors/__init__.py +0 -0
  532. skylos/rules/danger/danger_cors/cors_flow.py +185 -0
  533. skylos/rules/danger/danger_fs/__init__.py +0 -0
  534. skylos/rules/danger/danger_fs/path_flow.py +1115 -0
  535. skylos/rules/danger/danger_fs/pytest_paths.py +355 -0
  536. skylos/rules/danger/danger_jwt/__init__.py +0 -0
  537. skylos/rules/danger/danger_jwt/jwt_flow.py +72 -0
  538. skylos/rules/danger/danger_jwt/jwt_provenance.py +676 -0
  539. skylos/rules/danger/danger_llm/__init__.py +2 -0
  540. skylos/rules/danger/danger_llm/consumption.py +357 -0
  541. skylos/rules/danger/danger_llm/llm_flow.py +384 -0
  542. skylos/rules/danger/danger_llm/sensitivity.py +96 -0
  543. skylos/rules/danger/danger_llm/utils.py +196 -0
  544. skylos/rules/danger/danger_mcp/__init__.py +0 -0
  545. skylos/rules/danger/danger_mcp/mcp_flow.py +355 -0
  546. skylos/rules/danger/danger_ml/__init__.py +1 -0
  547. skylos/rules/danger/danger_ml/model_deserialization.py +363 -0
  548. skylos/rules/danger/danger_net/__init__.py +0 -0
  549. skylos/rules/danger/danger_net/ssrf_flow.py +2334 -0
  550. skylos/rules/danger/danger_redirect/__init__.py +0 -0
  551. skylos/rules/danger/danger_redirect/redirect_flow.py +161 -0
  552. skylos/rules/danger/danger_sql/__init__.py +0 -0
  553. skylos/rules/danger/danger_sql/sql_flow.py +980 -0
  554. skylos/rules/danger/danger_sql/sql_raw_flow.py +223 -0
  555. skylos/rules/danger/danger_sql/sqlalchemy_provenance.py +311 -0
  556. skylos/rules/danger/danger_web/__init__.py +0 -0
  557. skylos/rules/danger/danger_web/xss_flow.py +274 -0
  558. skylos/rules/danger/danger_webhook/__init__.py +1 -0
  559. skylos/rules/danger/danger_webhook/webhook_flow.py +239 -0
  560. skylos/rules/danger/module_namespace.py +485 -0
  561. skylos/rules/danger/taint.py +293 -0
  562. skylos/rules/danger/untrusted_sources.py +907 -0
  563. skylos/rules/quality/__init__.py +0 -0
  564. skylos/rules/quality/_function_defaults.py +208 -0
  565. skylos/rules/quality/_object_auth.py +758 -0
  566. skylos/rules/quality/_protocols.py +754 -0
  567. skylos/rules/quality/_readability.py +602 -0
  568. skylos/rules/quality/async_blocking.py +138 -0
  569. skylos/rules/quality/class_size.py +212 -0
  570. skylos/rules/quality/clones.py +551 -0
  571. skylos/rules/quality/code_health.py +221 -0
  572. skylos/rules/quality/cohesion.py +435 -0
  573. skylos/rules/quality/complexity.py +280 -0
  574. skylos/rules/quality/concurrency.py +348 -0
  575. skylos/rules/quality/coupling.py +477 -0
  576. skylos/rules/quality/logic.py +63 -0
  577. skylos/rules/quality/logic_foundation.py +2036 -0
  578. skylos/rules/quality/logic_maintainability.py +857 -0
  579. skylos/rules/quality/logic_security.py +2138 -0
  580. skylos/rules/quality/nesting.py +117 -0
  581. skylos/rules/quality/performance.py +315 -0
  582. skylos/rules/quality/policy.py +324 -0
  583. skylos/rules/quality/practices.py +624 -0
  584. skylos/rules/quality/regression.py +929 -0
  585. skylos/rules/quality/standards.py +216 -0
  586. skylos/rules/quality/structure.py +141 -0
  587. skylos/rules/quality/unreachable.py +229 -0
  588. skylos/rules/quality/unused_deps.py +742 -0
  589. skylos/rules/sca/__init__.py +0 -0
  590. skylos/rules/sca/advisory_metadata.py +310 -0
  591. skylos/rules/sca/bun_lockfile.py +289 -0
  592. skylos/rules/sca/licenses.py +982 -0
  593. skylos/rules/sca/lockfile_types.py +42 -0
  594. skylos/rules/sca/npm_lockfile.py +520 -0
  595. skylos/rules/sca/osv_client.py +356 -0
  596. skylos/rules/sca/pipfile_lockfile.py +239 -0
  597. skylos/rules/sca/pnpm_lockfile.py +1070 -0
  598. skylos/rules/sca/poetry_lockfile.py +466 -0
  599. skylos/rules/sca/publisher_changes.py +317 -0
  600. skylos/rules/sca/reachability.py +132 -0
  601. skylos/rules/sca/uv_lockfile.py +586 -0
  602. skylos/rules/sca/vulnerability_scanner.py +2182 -0
  603. skylos/rules/sca/yarn_lockfile.py +502 -0
  604. skylos/rules/secret_shapes.py +617 -0
  605. skylos/rules/secrets.py +4544 -0
  606. skylos/rules/vibe_dictionary.py +426 -0
  607. skylos/scale/__init__.py +0 -0
  608. skylos/scale/parallel_static.py +411 -0
  609. skylos/security/__init__.py +1 -0
  610. skylos/security/agent_instruction_paths.py +148 -0
  611. skylos/security/auth_regressions.py +352 -0
  612. skylos/security/canonicalize.py +166 -0
  613. skylos/security/command_guard.py +90 -0
  614. skylos/security/command_guard_exfil.py +680 -0
  615. skylos/security/command_guard_parse.py +350 -0
  616. skylos/security/command_guard_paths.py +227 -0
  617. skylos/security/command_guard_policy.py +376 -0
  618. skylos/security/command_guard_types.py +58 -0
  619. skylos/security/contracts.py +467 -0
  620. skylos/security/injection_scanner.py +585 -0
  621. skylos/security/regression_diff.py +146 -0
  622. skylos/security/regression_gate.py +86 -0
  623. skylos/ui/__init__.py +1 -0
  624. skylos/ui/clipboard.py +75 -0
  625. skylos/ui/dead_code_evidence.py +239 -0
  626. skylos/ui/help.py +626 -0
  627. skylos/ui/nudge.py +189 -0
  628. skylos/ui/quality_advice.py +35 -0
  629. skylos/ui/rich_report.py +1097 -0
  630. skylos/ui/scope_notes.py +107 -0
  631. skylos/ui/security_evidence.py +81 -0
  632. skylos/ui/terminal_report.py +873 -0
  633. skylos/ui/tour.py +131 -0
  634. skylos/ui/tui.py +918 -0
  635. skylos/verdict.py +459 -0
  636. skylos/verification/__init__.py +1 -0
  637. skylos/verification/behavior.py +786 -0
  638. skylos/verification/changes.py +92 -0
  639. skylos/verification/comparison.py +470 -0
  640. skylos/verification/context.py +440 -0
  641. skylos/verification/explanations.py +160 -0
  642. skylos/verification/refactor.py +460 -0
  643. skylos/verification/render.py +248 -0
  644. skylos/verification/windows_snapshot.py +448 -0
  645. skylos/verify_change.py +828 -0
  646. skylos/visitors/__init__.py +0 -0
  647. skylos/visitors/base.py +3143 -0
  648. skylos/visitors/framework_aware.py +1078 -0
  649. skylos/visitors/languages/__init__.py +0 -0
  650. skylos/visitors/languages/cpp/__init__.py +117 -0
  651. skylos/visitors/languages/cpp/core.py +199 -0
  652. skylos/visitors/languages/csharp/__init__.py +82 -0
  653. skylos/visitors/languages/csharp/_lex.py +144 -0
  654. skylos/visitors/languages/csharp/core.py +793 -0
  655. skylos/visitors/languages/csharp/danger.py +640 -0
  656. skylos/visitors/languages/csharp/quality.py +121 -0
  657. skylos/visitors/languages/csharp/reachability.py +286 -0
  658. skylos/visitors/languages/dart/__init__.py +89 -0
  659. skylos/visitors/languages/dart/core.py +750 -0
  660. skylos/visitors/languages/dart/danger.py +248 -0
  661. skylos/visitors/languages/go/__init__.py +5 -0
  662. skylos/visitors/languages/go/go.py +241 -0
  663. skylos/visitors/languages/go/quality.py +217 -0
  664. skylos/visitors/languages/java/__init__.py +90 -0
  665. skylos/visitors/languages/java/core.py +715 -0
  666. skylos/visitors/languages/java/danger.py +1855 -0
  667. skylos/visitors/languages/java/flow.py +2345 -0
  668. skylos/visitors/languages/java/properties.py +239 -0
  669. skylos/visitors/languages/java/quality.py +286 -0
  670. skylos/visitors/languages/java/source_helpers.py +359 -0
  671. skylos/visitors/languages/kotlin/__init__.py +104 -0
  672. skylos/visitors/languages/kotlin/_lex.py +35 -0
  673. skylos/visitors/languages/kotlin/core.py +284 -0
  674. skylos/visitors/languages/php/__init__.py +103 -0
  675. skylos/visitors/languages/php/blade.py +61 -0
  676. skylos/visitors/languages/php/core.py +1438 -0
  677. skylos/visitors/languages/php/danger.py +214 -0
  678. skylos/visitors/languages/php/laravel.py +351 -0
  679. skylos/visitors/languages/rust/__init__.py +89 -0
  680. skylos/visitors/languages/rust/core.py +1656 -0
  681. skylos/visitors/languages/rust/danger.py +267 -0
  682. skylos/visitors/languages/shell/__init__.py +80 -0
  683. skylos/visitors/languages/shell/danger.py +582 -0
  684. skylos/visitors/languages/statement_scan.py +162 -0
  685. skylos/visitors/languages/typescript/__init__.py +372 -0
  686. skylos/visitors/languages/typescript/analysis.py +2270 -0
  687. skylos/visitors/languages/typescript/conventions.py +305 -0
  688. skylos/visitors/languages/typescript/core.py +1537 -0
  689. skylos/visitors/languages/typescript/danger.py +10784 -0
  690. skylos/visitors/languages/typescript/esbuild_static.py +764 -0
  691. skylos/visitors/languages/typescript/express_taint.py +881 -0
  692. skylos/visitors/languages/typescript/framework.py +553 -0
  693. skylos/visitors/languages/typescript/grammar_gaps.py +646 -0
  694. skylos/visitors/languages/typescript/nextjs.py +520 -0
  695. skylos/visitors/languages/typescript/quality.py +647 -0
  696. skylos/visitors/languages/typescript/quality_signals.py +2464 -0
  697. skylos/visitors/languages/typescript/resolve.py +681 -0
  698. skylos/visitors/languages/typescript/safe_glob.py +83 -0
  699. skylos/visitors/languages/typescript/security_flow.py +3564 -0
  700. skylos/visitors/languages/typescript/security_proofs.py +3651 -0
  701. skylos/visitors/languages/typescript/source_lines.py +19 -0
  702. skylos/visitors/languages/typescript/tool_configs.py +68 -0
  703. skylos/visitors/languages/typescript/type_safety.py +633 -0
  704. skylos/visitors/languages/typescript/workspace.py +567 -0
  705. skylos/visitors/registration_decorators.py +169 -0
  706. skylos/visitors/test_aware.py +76 -0
  707. skylos-4.50.0.dist-info/METADATA +1357 -0
  708. skylos-4.50.0.dist-info/RECORD +717 -0
  709. skylos-4.50.0.dist-info/WHEEL +5 -0
  710. skylos-4.50.0.dist-info/entry_points.txt +2 -0
  711. skylos-4.50.0.dist-info/licenses/AUTHORS.md +1 -0
  712. skylos-4.50.0.dist-info/licenses/LICENSE +190 -0
  713. skylos-4.50.0.dist-info/top_level.txt +2 -0
  714. skylos_mcp/__init__.py +0 -0
  715. skylos_mcp/__main__.py +4 -0
  716. skylos_mcp/auth.py +340 -0
  717. skylos_mcp/server.py +2095 -0
skylos/__init__.py ADDED
@@ -0,0 +1,39 @@
1
+ from importlib import metadata
2
+ from pathlib import Path
3
+ import re
4
+
5
+
6
+ def _version_from_pyproject() -> str | None:
7
+ pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml"
8
+ try:
9
+ contents = pyproject.read_text(encoding="utf-8")
10
+ except OSError:
11
+ return None
12
+ match = re.search(r'(?m)^version\s*=\s*"([^"]+)"', contents)
13
+ return match.group(1) if match else None
14
+
15
+
16
+ def _resolve_version() -> str:
17
+ local_version = _version_from_pyproject()
18
+ if local_version:
19
+ return local_version
20
+ try:
21
+ return metadata.version("skylos")
22
+ except metadata.PackageNotFoundError:
23
+ return "0+unknown"
24
+
25
+
26
+ __version__ = _resolve_version()
27
+
28
+
29
+ def analyze(*args, **kwargs):
30
+ from .analyzer import analyze as _analyze
31
+
32
+ return _analyze(*args, **kwargs)
33
+
34
+
35
+ def debug_test():
36
+ return "debug-ok"
37
+
38
+
39
+ __all__ = ["analyze", "debug_test", "__version__"]
@@ -0,0 +1,8 @@
1
+ from .base import BaseAdapter
2
+ from .litellm_adapter import LiteLLMAdapter
3
+
4
+ __all__ = ["BaseAdapter", "get_adapter", "LiteLLMAdapter"]
5
+
6
+
7
+ def get_adapter(model, api_key=None, api_base=None):
8
+ return LiteLLMAdapter(model, api_key, api_base)
@@ -0,0 +1,11 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class BaseAdapter(ABC):
5
+ def __init__(self, model, api_key):
6
+ self.model = model
7
+ self.api_key = api_key
8
+
9
+ @abstractmethod
10
+ def complete(self, system_prompt, user_prompt, response_format=None):
11
+ pass
@@ -0,0 +1,528 @@
1
+ import os
2
+ import time
3
+ from .base import BaseAdapter
4
+ from skylos.cloud.credentials import get_key, PROVIDERS
5
+ from skylos.llm.completion_diagnostics import (
6
+ OUTPUT_BUDGET_FINISH_REASON,
7
+ OUTPUT_BUDGET_SIGNAL,
8
+ normalize_finish_reason,
9
+ )
10
+
11
+
12
+ class LiteLLMAdapter(BaseAdapter):
13
+ MAX_DIAGNOSTIC_COUNT = 1_000_000_000
14
+ RETRYABLE_ERROR_SNIPPETS = (
15
+ "connection error",
16
+ "connection refused",
17
+ "failed to establish a new connection",
18
+ "name or service not known",
19
+ "nodename nor servname provided",
20
+ "timed out",
21
+ "timeout",
22
+ "service unavailable",
23
+ "internalservererror",
24
+ "server error",
25
+ "overloaded",
26
+ "rate limit",
27
+ "ratelimit",
28
+ "429",
29
+ )
30
+
31
+ def __init__(
32
+ self,
33
+ model,
34
+ api_key=None,
35
+ api_base=None,
36
+ provider=None,
37
+ enable_cache=True,
38
+ max_tokens=None,
39
+ timeout=None,
40
+ retry_attempts=3,
41
+ temperature=0.0,
42
+ reasoning_effort=None,
43
+ ):
44
+ super().__init__(model, api_key)
45
+ self.enable_cache = enable_cache
46
+ self.max_tokens = max_tokens
47
+ self.timeout = timeout
48
+ self.retry_attempts = max(1, int(retry_attempts or 1))
49
+ self.temperature = temperature
50
+ self.reasoning_effort = reasoning_effort
51
+ self.last_usage = {
52
+ "prompt_tokens": 0,
53
+ "completion_tokens": 0,
54
+ "total_tokens": 0,
55
+ }
56
+ self.last_completion_diagnostic = self._empty_completion_diagnostic()
57
+ self.total_usage = {
58
+ "prompt_tokens": 0,
59
+ "completion_tokens": 0,
60
+ "total_tokens": 0,
61
+ }
62
+ self.explicit_provider = (provider or "").strip().lower() or None
63
+
64
+ os.environ.setdefault("LITELLM_LOCAL_MODEL_COST_MAP", "true")
65
+ try:
66
+ import litellm
67
+
68
+ self.litellm = litellm
69
+ self.litellm.drop_params = True
70
+ except ImportError:
71
+ raise ImportError(
72
+ "LiteLLM is required for this feature. "
73
+ "Install it with: pip install skylos[llm]"
74
+ )
75
+
76
+ self.api_base = api_base or os.getenv("SKYLOS_LLM_BASE_URL")
77
+ self._resolve_api_key()
78
+
79
+ def _detect_provider(self):
80
+ if self.explicit_provider:
81
+ return self.explicit_provider
82
+
83
+ model = (self.model or "").lower()
84
+
85
+ if model.startswith("ollama/"):
86
+ return "ollama"
87
+ if "claude" in model:
88
+ return "anthropic"
89
+ if model.startswith("gemini/"):
90
+ return "google"
91
+ if model.startswith("mistral/"):
92
+ return "mistral"
93
+ if model.startswith("groq/"):
94
+ return "groq"
95
+
96
+ return "openai"
97
+
98
+ def _is_local(self):
99
+ model = (self.model or "").strip().lower()
100
+ if model.startswith("ollama/"):
101
+ return True
102
+
103
+ base_url = (self.api_base or "").strip().lower()
104
+ if base_url:
105
+ if "localhost" in base_url:
106
+ return True
107
+ if "127.0.0.1" in base_url:
108
+ return True
109
+
110
+ return False
111
+
112
+ def _is_anthropic(self):
113
+ return self._detect_provider() == "anthropic"
114
+
115
+ def _get_provider_env_var(self, provider):
116
+ if not provider:
117
+ return None
118
+ return PROVIDERS.get(provider)
119
+
120
+ def _resolve_api_key(self):
121
+ if self._is_local():
122
+ return
123
+
124
+ if self.api_key:
125
+ self._set_provider_env_var_if_missing(self.api_key)
126
+ return
127
+
128
+ provider = self._detect_provider()
129
+ env_var = self._get_provider_env_var(provider)
130
+
131
+ if env_var:
132
+ env_value = os.getenv(env_var)
133
+ if env_value:
134
+ self.api_key = env_value
135
+ return
136
+
137
+ keyring_key = get_key(provider)
138
+ if keyring_key:
139
+ if env_var:
140
+ os.environ[env_var] = keyring_key
141
+ self.api_key = keyring_key
142
+ return
143
+
144
+ def _set_provider_env_var_if_missing(self, key):
145
+ if not key:
146
+ return
147
+
148
+ provider = self._detect_provider()
149
+ env_var = self._get_provider_env_var(provider)
150
+
151
+ if not env_var:
152
+ return
153
+
154
+ existing = os.getenv(env_var)
155
+ if existing:
156
+ return
157
+
158
+ os.environ[env_var] = key
159
+
160
+ def _missing_key_message(self):
161
+ provider = self._detect_provider()
162
+ env_var = self._get_provider_env_var(provider)
163
+
164
+ if env_var:
165
+ return (
166
+ "No API key found for provider '{}'.\n"
167
+ "Set {} or run 'skylos key' and select '{}'."
168
+ ).format(provider, env_var, provider)
169
+
170
+ return (
171
+ "No API key found for provider '{}'.\nRun 'skylos key' and select '{}'."
172
+ ).format(provider, provider)
173
+
174
+ def _looks_like_auth_error(self, message):
175
+ if not message:
176
+ return False
177
+
178
+ msg = message.lower()
179
+
180
+ if "unauthorized" in msg:
181
+ return True
182
+ if "invalid api key" in msg:
183
+ return True
184
+ if "incorrect api key" in msg:
185
+ return True
186
+ if "authentication" in msg:
187
+ return True
188
+ if "401" in msg:
189
+ return True
190
+ if "403" in msg:
191
+ return True
192
+
193
+ return False
194
+
195
+ def _looks_like_connection_error(self, message):
196
+ if not message:
197
+ return False
198
+
199
+ msg = message.lower()
200
+
201
+ if "connection refused" in msg:
202
+ return True
203
+ if "failed to establish a new connection" in msg:
204
+ return True
205
+ if "name or service not known" in msg:
206
+ return True
207
+ if "nodename nor servname provided" in msg:
208
+ return True
209
+ if "timed out" in msg:
210
+ return True
211
+
212
+ return False
213
+
214
+ def _should_retry_exception(self, exc):
215
+ msg = str(exc or "").lower()
216
+ if not msg:
217
+ return False
218
+ return any(snippet in msg for snippet in self.RETRYABLE_ERROR_SNIPPETS)
219
+
220
+ def _retry_delay(self, attempt):
221
+ return min(0.5 * (2**attempt), 2.0)
222
+
223
+ def reset_usage(self):
224
+ self.last_usage = {
225
+ "prompt_tokens": 0,
226
+ "completion_tokens": 0,
227
+ "total_tokens": 0,
228
+ }
229
+ self._reset_completion_diagnostic()
230
+ self.total_usage = {
231
+ "prompt_tokens": 0,
232
+ "completion_tokens": 0,
233
+ "total_tokens": 0,
234
+ }
235
+
236
+ def _normalize_usage(self, usage):
237
+ if usage is None:
238
+ return {
239
+ "prompt_tokens": 0,
240
+ "completion_tokens": 0,
241
+ "total_tokens": 0,
242
+ }
243
+
244
+ if isinstance(usage, dict):
245
+ prompt = int(usage.get("prompt_tokens") or 0)
246
+ completion = int(usage.get("completion_tokens") or 0)
247
+ total = int(usage.get("total_tokens") or (prompt + completion))
248
+ return {
249
+ "prompt_tokens": max(prompt, 0),
250
+ "completion_tokens": max(completion, 0),
251
+ "total_tokens": max(total, 0),
252
+ }
253
+
254
+ prompt = int(getattr(usage, "prompt_tokens", 0) or 0)
255
+ completion = int(getattr(usage, "completion_tokens", 0) or 0)
256
+ total = int(getattr(usage, "total_tokens", 0) or (prompt + completion))
257
+ return {
258
+ "prompt_tokens": max(prompt, 0),
259
+ "completion_tokens": max(completion, 0),
260
+ "total_tokens": max(total, 0),
261
+ }
262
+
263
+ def _record_usage(self, response):
264
+ usage = self._normalize_usage(getattr(response, "usage", None))
265
+ self.last_usage = usage
266
+ for key, value in usage.items():
267
+ self.total_usage[key] += value
268
+
269
+ @staticmethod
270
+ def _field(value, name):
271
+ if isinstance(value, dict):
272
+ return value.get(name)
273
+ return getattr(value, name, None)
274
+
275
+ @classmethod
276
+ def _bounded_count(cls, value):
277
+ if isinstance(value, bool) or not isinstance(value, int | float):
278
+ return None
279
+ try:
280
+ count = int(value)
281
+ except (OverflowError, ValueError):
282
+ return None
283
+ if count < 0 or count > cls.MAX_DIAGNOSTIC_COUNT:
284
+ return None
285
+ return count
286
+
287
+ @classmethod
288
+ def _finish_reason(cls, choice):
289
+ return normalize_finish_reason(cls._field(choice, "finish_reason"))
290
+
291
+ @staticmethod
292
+ def _empty_completion_diagnostic():
293
+ return {
294
+ "finish_reason": None,
295
+ "content_chars": None,
296
+ "completion_tokens": None,
297
+ "reasoning_tokens": None,
298
+ "signal": None,
299
+ }
300
+
301
+ def _reset_completion_diagnostic(self):
302
+ self.last_completion_diagnostic = self._empty_completion_diagnostic()
303
+
304
+ def _record_completion_diagnostic(self, response, *, choice, content):
305
+ usage = self._field(response, "usage")
306
+ completion_details = self._field(usage, "completion_tokens_details")
307
+ completion_tokens = self._bounded_count(self._field(usage, "completion_tokens"))
308
+ reasoning_tokens = self._bounded_count(
309
+ self._field(completion_details, "reasoning_tokens")
310
+ )
311
+ finish_reason = self._finish_reason(choice)
312
+ normalized_content = content.strip() if isinstance(content, str) else ""
313
+ content_chars = len(normalized_content) if content is not None else 0
314
+ signal = (
315
+ OUTPUT_BUDGET_SIGNAL
316
+ if finish_reason == OUTPUT_BUDGET_FINISH_REASON
317
+ else None
318
+ )
319
+ self.last_completion_diagnostic = {
320
+ "finish_reason": finish_reason,
321
+ "content_chars": content_chars,
322
+ "completion_tokens": completion_tokens,
323
+ "reasoning_tokens": reasoning_tokens,
324
+ "signal": signal,
325
+ }
326
+
327
+ def _complete_once(self, system_prompt, user_prompt, response_format=None):
328
+ self._resolve_api_key()
329
+
330
+ if (not self._is_local()) and (not self.api_key):
331
+ return self._missing_key_message()
332
+
333
+ if self.enable_cache and self._is_anthropic():
334
+ messages = [
335
+ {
336
+ "role": "system",
337
+ "content": [
338
+ {
339
+ "type": "text",
340
+ "text": system_prompt,
341
+ "cache_control": {"type": "ephemeral"},
342
+ }
343
+ ],
344
+ },
345
+ {"role": "user", "content": user_prompt},
346
+ ]
347
+ else:
348
+ messages = [
349
+ {"role": "system", "content": system_prompt},
350
+ {"role": "user", "content": user_prompt},
351
+ ]
352
+
353
+ kwargs = {
354
+ "model": self.model,
355
+ "messages": messages,
356
+ "temperature": self.temperature,
357
+ "api_key": self.api_key,
358
+ }
359
+
360
+ if self.explicit_provider is not None:
361
+ # New model aliases may not exist in the bundled LiteLLM model map
362
+ # yet. Preserve the caller's explicit provider so a valid model
363
+ # such as ``gpt-5.4`` is routed without requiring a transport-only
364
+ # ``openai/`` prefix.
365
+ kwargs["custom_llm_provider"] = self.explicit_provider
366
+
367
+ if self.max_tokens is not None:
368
+ kwargs["max_tokens"] = self.max_tokens
369
+ if self.timeout is not None:
370
+ kwargs["timeout"] = self.timeout
371
+ if self.reasoning_effort is not None:
372
+ kwargs["reasoning_effort"] = self.reasoning_effort
373
+
374
+ if self.api_base:
375
+ kwargs["api_base"] = self.api_base
376
+
377
+ if self._is_local():
378
+ kwargs["api_key"] = "not-needed"
379
+
380
+ if response_format is not None:
381
+ kwargs["response_format"] = response_format
382
+
383
+ response = self.litellm.completion(**kwargs)
384
+ self._record_usage(response)
385
+ choices = self._field(response, "choices")
386
+ choice = choices[0]
387
+ message = self._field(choice, "message")
388
+ content = self._field(message, "content")
389
+ self._record_completion_diagnostic(
390
+ response,
391
+ choice=choice,
392
+ content=content,
393
+ )
394
+ if content is None:
395
+ return ""
396
+ if not isinstance(content, str):
397
+ raise TypeError("LiteLLM completion content must be text or null")
398
+ return content.strip()
399
+
400
+ def _stream_once(self, system_prompt, user_prompt):
401
+ self._resolve_api_key()
402
+
403
+ if (not self._is_local()) and (not self.api_key):
404
+ yield self._missing_key_message()
405
+ return
406
+
407
+ if self.enable_cache and self._is_anthropic():
408
+ messages = [
409
+ {
410
+ "role": "system",
411
+ "content": [
412
+ {
413
+ "type": "text",
414
+ "text": system_prompt,
415
+ "cache_control": {"type": "ephemeral"},
416
+ }
417
+ ],
418
+ },
419
+ {"role": "user", "content": user_prompt},
420
+ ]
421
+ else:
422
+ messages = [
423
+ {"role": "system", "content": system_prompt},
424
+ {"role": "user", "content": user_prompt},
425
+ ]
426
+
427
+ kwargs = {
428
+ "model": self.model,
429
+ "messages": messages,
430
+ "temperature": self.temperature,
431
+ "stream": True,
432
+ "api_key": self.api_key,
433
+ }
434
+
435
+ if self.explicit_provider is not None:
436
+ kwargs["custom_llm_provider"] = self.explicit_provider
437
+
438
+ if self.max_tokens is not None:
439
+ kwargs["max_tokens"] = self.max_tokens
440
+ if self.timeout is not None:
441
+ kwargs["timeout"] = self.timeout
442
+ if self.reasoning_effort is not None:
443
+ kwargs["reasoning_effort"] = self.reasoning_effort
444
+
445
+ if self.api_base:
446
+ kwargs["api_base"] = self.api_base
447
+
448
+ if self._is_local():
449
+ kwargs["api_key"] = "not-needed"
450
+
451
+ response = self.litellm.completion(**kwargs)
452
+ for chunk in response:
453
+ if chunk.choices[0].delta.content:
454
+ yield chunk.choices[0].delta.content
455
+
456
+ def _format_exception_message(self, exc):
457
+ text = str(exc)
458
+
459
+ if (not self._is_local()) and (not self.api_key):
460
+ return self._missing_key_message()
461
+
462
+ if self._looks_like_auth_error(text):
463
+ provider = self._detect_provider()
464
+ return "Error: {}\n\nRun 'skylos key' and select '{}'.".format(
465
+ text, provider
466
+ )
467
+
468
+ if self._looks_like_connection_error(text):
469
+ if self.api_base:
470
+ return "Error: {}\n\nCheck SKYLOS_LLM_BASE_URL / --base-url: {}".format(
471
+ text, self.api_base
472
+ )
473
+ return (
474
+ "Error: {}\n\n"
475
+ "If you're using a local LLM, set SKYLOS_LLM_BASE_URL "
476
+ "(e.g. http://localhost:11434/v1)."
477
+ ).format(text)
478
+
479
+ return "Error: {}".format(text)
480
+
481
+ def complete(self, system_prompt, user_prompt, response_format=None):
482
+ # ``last_usage`` describes this completion only. Clear the previous
483
+ # response before attempting provider I/O so an error string cannot be
484
+ # charged with token counts left behind by an earlier successful call.
485
+ self.last_usage = {
486
+ "prompt_tokens": 0,
487
+ "completion_tokens": 0,
488
+ "total_tokens": 0,
489
+ }
490
+ self._reset_completion_diagnostic()
491
+ last_error = None
492
+ for attempt in range(self.retry_attempts):
493
+ self._reset_completion_diagnostic()
494
+ try:
495
+ return self._complete_once(
496
+ system_prompt,
497
+ user_prompt,
498
+ response_format=response_format,
499
+ )
500
+ except Exception as e:
501
+ self._reset_completion_diagnostic()
502
+ last_error = e
503
+ if (
504
+ not self._should_retry_exception(e)
505
+ or attempt == self.retry_attempts - 1
506
+ ):
507
+ return self._format_exception_message(e)
508
+ time.sleep(self._retry_delay(attempt))
509
+
510
+ return self._format_exception_message(last_error)
511
+
512
+ def stream(self, system_prompt, user_prompt):
513
+ last_error = None
514
+ for attempt in range(self.retry_attempts):
515
+ try:
516
+ yield from self._stream_once(system_prompt, user_prompt)
517
+ return
518
+ except Exception as e:
519
+ last_error = e
520
+ if (
521
+ not self._should_retry_exception(e)
522
+ or attempt == self.retry_attempts - 1
523
+ ):
524
+ yield self._format_exception_message(e)
525
+ return
526
+ time.sleep(self._retry_delay(attempt))
527
+
528
+ yield self._format_exception_message(last_error)
@@ -0,0 +1 @@
1
+ """Agent center state, payload, service, and triage helpers."""