alysis-code 0.13.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.
Files changed (458) hide show
  1. alysis_code/__init__.py +3 -0
  2. alysis_code/__main__.py +4 -0
  3. alysis_code/_build_info.py +14 -0
  4. alysis_code/account_login.py +468 -0
  5. alysis_code/agent/README.md +35 -0
  6. alysis_code/agent/__init__.py +11 -0
  7. alysis_code/agent/acceptance_contract.py +2217 -0
  8. alysis_code/agent/blast_radius.py +1403 -0
  9. alysis_code/agent/cache_keepalive.py +227 -0
  10. alysis_code/agent/completion_certificate.py +366 -0
  11. alysis_code/agent/completion_gate.py +306 -0
  12. alysis_code/agent/empty_response_stall.py +403 -0
  13. alysis_code/agent/errors.py +28 -0
  14. alysis_code/agent/llm_calls.py +475 -0
  15. alysis_code/agent/mutation_classification.py +227 -0
  16. alysis_code/agent/prompt_context.py +2508 -0
  17. alysis_code/agent/read_ledger.py +253 -0
  18. alysis_code/agent/regression_baseline.py +642 -0
  19. alysis_code/agent/reproduction_first.py +610 -0
  20. alysis_code/agent/sensitive_output.py +629 -0
  21. alysis_code/agent/session.py +3218 -0
  22. alysis_code/agent/steering.py +191 -0
  23. alysis_code/agent/subagent_execution.py +5177 -0
  24. alysis_code/agent/subagent_workspace.py +666 -0
  25. alysis_code/agent/tools_assembly.py +4728 -0
  26. alysis_code/agent/turn/__init__.py +101 -0
  27. alysis_code/agent/turn/core.py +8483 -0
  28. alysis_code/agent/turn/events.py +113 -0
  29. alysis_code/agent/turn/exploration.py +590 -0
  30. alysis_code/agent/turn/interventions.py +65 -0
  31. alysis_code/agent/turn/read_cache.py +420 -0
  32. alysis_code/agent/turn/snapshot.py +179 -0
  33. alysis_code/agent/turn_contract.py +661 -0
  34. alysis_code/agent/turn_path.py +129 -0
  35. alysis_code/agent/verification.py +2885 -0
  36. alysis_code/agent/verification_commands.py +512 -0
  37. alysis_code/agent/verification_evidence.py +738 -0
  38. alysis_code/agent_loop.py +693 -0
  39. alysis_code/agent_runtimes/__init__.py +51 -0
  40. alysis_code/agent_runtimes/base.py +114 -0
  41. alysis_code/agent_runtimes/builtins.py +129 -0
  42. alysis_code/agent_runtimes/codex_cli.py +664 -0
  43. alysis_code/agent_runtimes/host.py +263 -0
  44. alysis_code/agent_runtimes/registry.py +64 -0
  45. alysis_code/agent_runtimes/service.py +150 -0
  46. alysis_code/agentbox_client.py +416 -0
  47. alysis_code/agentbox_integration.py +310 -0
  48. alysis_code/alysis_cloud.py +152 -0
  49. alysis_code/approval_scope.py +276 -0
  50. alysis_code/assets/README.md +33 -0
  51. alysis_code/assets/__init__.py +126 -0
  52. alysis_code/assets/asset_read_core.py +281 -0
  53. alysis_code/assets/budget_allocator.py +456 -0
  54. alysis_code/assets/comprehender.py +759 -0
  55. alysis_code/assets/index.py +654 -0
  56. alysis_code/assets/ingestion.py +275 -0
  57. alysis_code/assets/legacy_migration.py +413 -0
  58. alysis_code/assets/models.py +263 -0
  59. alysis_code/assets/ocr.py +239 -0
  60. alysis_code/assets/owl/ascii/f-000.txt +13 -0
  61. alysis_code/assets/owl/ascii/f-001.txt +13 -0
  62. alysis_code/assets/owl/ascii/f-002.txt +13 -0
  63. alysis_code/assets/owl/ascii/f-003.txt +13 -0
  64. alysis_code/assets/owl/ascii/f-004.txt +13 -0
  65. alysis_code/assets/owl/ascii/f-005.txt +13 -0
  66. alysis_code/assets/owl/ascii/f-006.txt +13 -0
  67. alysis_code/assets/owl/ascii/f-007.txt +13 -0
  68. alysis_code/assets/owl/ascii/f-008.txt +13 -0
  69. alysis_code/assets/owl/ascii/f-009.txt +13 -0
  70. alysis_code/assets/owl/ascii/f-010.txt +13 -0
  71. alysis_code/assets/owl/ascii/f-011.txt +13 -0
  72. alysis_code/assets/owl/ascii/f-012.txt +13 -0
  73. alysis_code/assets/owl/ascii/f-013.txt +13 -0
  74. alysis_code/assets/owl/ascii/f-014.txt +13 -0
  75. alysis_code/assets/owl/ascii/f-015.txt +13 -0
  76. alysis_code/assets/owl/ascii/f-016.txt +13 -0
  77. alysis_code/assets/owl/ascii/f-017.txt +13 -0
  78. alysis_code/assets/owl/ascii/f-018.txt +13 -0
  79. alysis_code/assets/owl/ascii/f-019.txt +13 -0
  80. alysis_code/assets/owl/ascii/f-020.txt +13 -0
  81. alysis_code/assets/owl/index.html +98 -0
  82. alysis_code/assets/owl/show-owl.sh +761 -0
  83. alysis_code/assets/paths.py +49 -0
  84. alysis_code/assets/plan_binding.py +326 -0
  85. alysis_code/assets/planner_context.py +466 -0
  86. alysis_code/assets/planner_tools.py +184 -0
  87. alysis_code/assets/prompts.py +101 -0
  88. alysis_code/assets/replanner_context.py +239 -0
  89. alysis_code/assets/surface.py +521 -0
  90. alysis_code/assets/untrusted_content.py +48 -0
  91. alysis_code/assets/usage_logger.py +94 -0
  92. alysis_code/assets/worker_mirror.py +428 -0
  93. alysis_code/assets/worker_section.py +303 -0
  94. alysis_code/assets/worker_tools.py +468 -0
  95. alysis_code/atomic_io.py +83 -0
  96. alysis_code/auth_diagnostics.py +272 -0
  97. alysis_code/background_runner.py +366 -0
  98. alysis_code/branding.py +270 -0
  99. alysis_code/budget_policy.py +390 -0
  100. alysis_code/build_identity.py +465 -0
  101. alysis_code/builtin_hooks/__init__.py +7 -0
  102. alysis_code/builtin_hooks/notify_done_windows.py +65 -0
  103. alysis_code/bwrap_etc.py +76 -0
  104. alysis_code/cancellation.py +41 -0
  105. alysis_code/capabilities.py +137 -0
  106. alysis_code/chatgpt_codex_static_provider.py +133 -0
  107. alysis_code/cli.py +51 -0
  108. alysis_code/cli_impl/__init__.py +1 -0
  109. alysis_code/cli_impl/assets_cli.py +537 -0
  110. alysis_code/cli_impl/assets_modal.py +412 -0
  111. alysis_code/cli_impl/chat/__init__.py +156 -0
  112. alysis_code/cli_impl/chat/commands.py +2616 -0
  113. alysis_code/cli_impl/chat/loop.py +4508 -0
  114. alysis_code/cli_impl/chat/mid_turn_policy.py +125 -0
  115. alysis_code/cli_impl/chat/rendering.py +444 -0
  116. alysis_code/cli_impl/chat/state.py +124 -0
  117. alysis_code/cli_impl/chat_resume.py +830 -0
  118. alysis_code/cli_impl/chat_slash_completer.py +258 -0
  119. alysis_code/cli_impl/commands/__init__.py +11 -0
  120. alysis_code/cli_impl/commands/_shared.py +89 -0
  121. alysis_code/cli_impl/commands/auth.py +623 -0
  122. alysis_code/cli_impl/commands/chat_resume_helpers.py +1531 -0
  123. alysis_code/cli_impl/commands/chat_state.py +158 -0
  124. alysis_code/cli_impl/commands/chat_status.py +1248 -0
  125. alysis_code/cli_impl/commands/chat_terminal.py +942 -0
  126. alysis_code/cli_impl/commands/chat_tui_panels.py +1018 -0
  127. alysis_code/cli_impl/commands/cli_common.py +1223 -0
  128. alysis_code/cli_impl/commands/cli_surface.py +77 -0
  129. alysis_code/cli_impl/commands/config.py +131 -0
  130. alysis_code/cli_impl/commands/conventions.py +85 -0
  131. alysis_code/cli_impl/commands/execution_helpers.py +350 -0
  132. alysis_code/cli_impl/commands/extensions.py +401 -0
  133. alysis_code/cli_impl/commands/forge.py +1282 -0
  134. alysis_code/cli_impl/commands/forge_asset_view.py +121 -0
  135. alysis_code/cli_impl/commands/forge_helpers.py +1215 -0
  136. alysis_code/cli_impl/commands/hooks.py +737 -0
  137. alysis_code/cli_impl/commands/ide_bridge.py +31 -0
  138. alysis_code/cli_impl/commands/mcp.py +700 -0
  139. alysis_code/cli_impl/commands/profile.py +453 -0
  140. alysis_code/cli_impl/commands/prompt_helpers.py +307 -0
  141. alysis_code/cli_impl/commands/report.py +88 -0
  142. alysis_code/cli_impl/commands/root.py +1118 -0
  143. alysis_code/cli_impl/commands/sandbox.py +184 -0
  144. alysis_code/cli_impl/commands/server.py +54 -0
  145. alysis_code/cli_impl/commands/sessions.py +252 -0
  146. alysis_code/cli_impl/commands/skills.py +404 -0
  147. alysis_code/cli_impl/commands/startup.py +946 -0
  148. alysis_code/cli_impl/commands/tools.py +335 -0
  149. alysis_code/cli_impl/commands/update.py +364 -0
  150. alysis_code/cli_impl/commands/welcome.py +972 -0
  151. alysis_code/cli_impl/config_menu.py +3882 -0
  152. alysis_code/cli_impl/forge.py +4509 -0
  153. alysis_code/cli_impl/forge_recovery.py +485 -0
  154. alysis_code/cli_impl/setup_wizard.py +2409 -0
  155. alysis_code/cli_impl/tui/__init__.py +58 -0
  156. alysis_code/cli_impl/tui/app.py +4551 -0
  157. alysis_code/cli_impl/tui/config.py +32 -0
  158. alysis_code/cli_impl/tui/config_flow.py +2754 -0
  159. alysis_code/cli_impl/tui/config_overlay.py +566 -0
  160. alysis_code/cli_impl/tui/content.py +78 -0
  161. alysis_code/cli_impl/tui/footer.py +218 -0
  162. alysis_code/cli_impl/tui/forge_status.py +136 -0
  163. alysis_code/cli_impl/tui/markdown.py +244 -0
  164. alysis_code/cli_impl/tui/owl.py +109 -0
  165. alysis_code/cli_impl/tui/plan_meta.py +477 -0
  166. alysis_code/cli_impl/tui/setup_app.py +519 -0
  167. alysis_code/cli_impl/tui/setup_flow.py +1622 -0
  168. alysis_code/cli_impl/tui/state.py +101 -0
  169. alysis_code/cli_impl/tui/subagent_identity.py +66 -0
  170. alysis_code/cli_impl/tui/subagent_panel.py +186 -0
  171. alysis_code/cli_impl/tui/surface.py +796 -0
  172. alysis_code/cli_impl/tui/transcript.py +514 -0
  173. alysis_code/cli_impl/tui/update_prompt.py +79 -0
  174. alysis_code/cli_impl/tui/workspace_guard.py +384 -0
  175. alysis_code/clipboard.py +172 -0
  176. alysis_code/code_review.py +1211 -0
  177. alysis_code/compaction/__init__.py +28 -0
  178. alysis_code/compaction/conversation_compactor.py +2932 -0
  179. alysis_code/compaction/importance.py +177 -0
  180. alysis_code/compaction/settings.py +297 -0
  181. alysis_code/compaction/tool_output_offload.py +447 -0
  182. alysis_code/config.py +3509 -0
  183. alysis_code/conflict_auto_resolver.py +895 -0
  184. alysis_code/context/__init__.py +1 -0
  185. alysis_code/context/tool_schema_budgeter.py +220 -0
  186. alysis_code/crash_diagnostics.py +282 -0
  187. alysis_code/custom_tools/README.md +34 -0
  188. alysis_code/custom_tools/__init__.py +43 -0
  189. alysis_code/custom_tools/discovery.py +903 -0
  190. alysis_code/custom_tools/runtime.py +1516 -0
  191. alysis_code/custom_tools/session.py +227 -0
  192. alysis_code/custom_tools/trust.py +232 -0
  193. alysis_code/diff_paths.py +113 -0
  194. alysis_code/direction_change.py +293 -0
  195. alysis_code/dispatch_timing.py +306 -0
  196. alysis_code/durable_service_manager.py +1236 -0
  197. alysis_code/edit_discipline.py +659 -0
  198. alysis_code/error_text.py +73 -0
  199. alysis_code/execution_budget.py +411 -0
  200. alysis_code/execution_context.py +915 -0
  201. alysis_code/execution_deadline.py +1065 -0
  202. alysis_code/execution_shared.py +1904 -0
  203. alysis_code/extensions/README.md +30 -0
  204. alysis_code/extensions/__init__.py +93 -0
  205. alysis_code/extensions/activation.py +138 -0
  206. alysis_code/extensions/install.py +1436 -0
  207. alysis_code/extensions/manifest.py +487 -0
  208. alysis_code/extensions/models.py +74 -0
  209. alysis_code/extensions/paths.py +56 -0
  210. alysis_code/extensions/registry.json +4 -0
  211. alysis_code/extensions/registry.py +52 -0
  212. alysis_code/extensions/state.py +83 -0
  213. alysis_code/extensions/workspace_trust.py +101 -0
  214. alysis_code/failed_task_evidence.py +369 -0
  215. alysis_code/failure_category.py +315 -0
  216. alysis_code/feedback_report.py +1647 -0
  217. alysis_code/file_classification.py +485 -0
  218. alysis_code/forge.py +2064 -0
  219. alysis_code/forge_completion.py +362 -0
  220. alysis_code/forge_events.py +475 -0
  221. alysis_code/frontmatter_utils.py +95 -0
  222. alysis_code/git_evidence.py +1181 -0
  223. alysis_code/git_ops.py +560 -0
  224. alysis_code/git_safe.py +62 -0
  225. alysis_code/git_worktrees.py +190 -0
  226. alysis_code/hooks/README.md +33 -0
  227. alysis_code/hooks/__init__.py +67 -0
  228. alysis_code/hooks/audit.py +171 -0
  229. alysis_code/hooks/config.py +225 -0
  230. alysis_code/hooks/dispatcher.py +1110 -0
  231. alysis_code/hooks/models.py +447 -0
  232. alysis_code/hooks/trust.py +202 -0
  233. alysis_code/host_actions.py +543 -0
  234. alysis_code/host_browser.py +103 -0
  235. alysis_code/ide/__init__.py +5 -0
  236. alysis_code/ide/activity_events.py +399 -0
  237. alysis_code/ide/approvals.py +337 -0
  238. alysis_code/ide/artifacts.py +153 -0
  239. alysis_code/ide/browser_egress_proxy.py +1076 -0
  240. alysis_code/ide/cdp_websocket_transport.py +1192 -0
  241. alysis_code/ide/change_ledger.py +1721 -0
  242. alysis_code/ide/context_blocks.py +979 -0
  243. alysis_code/ide/event_stream.py +531 -0
  244. alysis_code/ide/forge_protocol.py +3112 -0
  245. alysis_code/ide/forge_request_ledger.py +737 -0
  246. alysis_code/ide/health.py +965 -0
  247. alysis_code/ide/managed_browser.py +2251 -0
  248. alysis_code/ide/management_protocol.py +3414 -0
  249. alysis_code/ide/mcp_oauth_coordinator.py +744 -0
  250. alysis_code/ide/mcp_oauth_lifecycle.py +1504 -0
  251. alysis_code/ide/prompt_queue.py +1070 -0
  252. alysis_code/ide/protocol.py +191 -0
  253. alysis_code/ide/resumable_swarm.py +1543 -0
  254. alysis_code/ide/session_search.py +295 -0
  255. alysis_code/ide/stdio_bridge.py +9935 -0
  256. alysis_code/ide/structured_state.py +1579 -0
  257. alysis_code/ide/swarm_protocol.py +816 -0
  258. alysis_code/integration_gate.py +506 -0
  259. alysis_code/interactive_input_guard.py +39 -0
  260. alysis_code/interactive_plan_mode.py +26 -0
  261. alysis_code/internal_artifacts.py +179 -0
  262. alysis_code/knowledge_base.py +1409 -0
  263. alysis_code/knowledge_capture.py +1190 -0
  264. alysis_code/knowledge_librarian.py +605 -0
  265. alysis_code/language_policy.py +34 -0
  266. alysis_code/litellm_static_provider.py +535 -0
  267. alysis_code/llm/__init__.py +1 -0
  268. alysis_code/llm/anthropic_messages.py +2288 -0
  269. alysis_code/llm/base.py +71 -0
  270. alysis_code/llm/cache_capabilities.py +985 -0
  271. alysis_code/llm/cache_control_blocks.py +244 -0
  272. alysis_code/llm/cache_policy.py +388 -0
  273. alysis_code/llm/factory.py +373 -0
  274. alysis_code/llm/gemini_generate_content.py +2652 -0
  275. alysis_code/llm/gemini_interactions.py +739 -0
  276. alysis_code/llm/metadata.py +450 -0
  277. alysis_code/llm/openai_compat.py +2947 -0
  278. alysis_code/llm/openai_responses.py +2604 -0
  279. alysis_code/llm/protocols.py +609 -0
  280. alysis_code/llm/provider_limits.py +525 -0
  281. alysis_code/llm/request_plan.py +389 -0
  282. alysis_code/llm/request_shape.py +238 -0
  283. alysis_code/llm/streaming.py +108 -0
  284. alysis_code/llm/temperature_compat.py +78 -0
  285. alysis_code/llm/types.py +195 -0
  286. alysis_code/llm/usage_normalization.py +222 -0
  287. alysis_code/llm_error_display.py +315 -0
  288. alysis_code/logging_redaction.py +326 -0
  289. alysis_code/managed_host_deadline.py +196 -0
  290. alysis_code/mcp/README.md +33 -0
  291. alysis_code/mcp/__init__.py +24 -0
  292. alysis_code/mcp/client.py +1137 -0
  293. alysis_code/mcp/config.py +597 -0
  294. alysis_code/mcp/errors.py +113 -0
  295. alysis_code/mcp/forge_scope.py +154 -0
  296. alysis_code/mcp/jsonrpc.py +214 -0
  297. alysis_code/mcp/manager.py +2308 -0
  298. alysis_code/mcp/models.py +666 -0
  299. alysis_code/mcp/oauth.py +972 -0
  300. alysis_code/mcp/oauth_runtime.py +310 -0
  301. alysis_code/mcp/oauth_store.py +276 -0
  302. alysis_code/mcp/prompts.py +329 -0
  303. alysis_code/mcp/resources.py +295 -0
  304. alysis_code/mcp/roots.py +106 -0
  305. alysis_code/mcp/server_requests.py +75 -0
  306. alysis_code/mcp/token_store.py +859 -0
  307. alysis_code/mcp/transport_http.py +1338 -0
  308. alysis_code/mcp/transport_stdio.py +1267 -0
  309. alysis_code/mcp/untrusted_content.py +119 -0
  310. alysis_code/merge_conflict_reviewer.py +729 -0
  311. alysis_code/model_catalog/__init__.py +1 -0
  312. alysis_code/model_catalog/chatgpt_codex_subscription_snapshot.json +186 -0
  313. alysis_code/model_catalog/litellm_model_prices_snapshot.json +44715 -0
  314. alysis_code/model_catalog/litellm_model_prices_snapshot.meta.json +17 -0
  315. alysis_code/model_metadata_policy.py +223 -0
  316. alysis_code/model_metadata_utils.py +103 -0
  317. alysis_code/model_registry.py +1420 -0
  318. alysis_code/model_router.py +147 -0
  319. alysis_code/permission_policy.py +1016 -0
  320. alysis_code/personas.py +451 -0
  321. alysis_code/pipeline_facts.py +233 -0
  322. alysis_code/plan_assistant.py +4763 -0
  323. alysis_code/plan_mode.py +393 -0
  324. alysis_code/plan_reconciliation.py +1228 -0
  325. alysis_code/plan_repair.py +652 -0
  326. alysis_code/plan_validation.py +1099 -0
  327. alysis_code/planning_constraints.py +904 -0
  328. alysis_code/policy.py +95 -0
  329. alysis_code/preview_server.py +457 -0
  330. alysis_code/process_reaping.py +566 -0
  331. alysis_code/profile_presets.py +1834 -0
  332. alysis_code/profiles.py +666 -0
  333. alysis_code/provider_auth/__init__.py +29 -0
  334. alysis_code/provider_auth/base.py +99 -0
  335. alysis_code/provider_auth/openai_codex.py +951 -0
  336. alysis_code/provider_auth/registry.py +76 -0
  337. alysis_code/provider_auth/store.py +125 -0
  338. alysis_code/provider_diagnostics.py +1209 -0
  339. alysis_code/provider_model_catalog.py +685 -0
  340. alysis_code/provider_telemetry.py +1699 -0
  341. alysis_code/provider_url.py +75 -0
  342. alysis_code/reasoning_contracts.py +911 -0
  343. alysis_code/remote_sync.py +350 -0
  344. alysis_code/replanning.py +1195 -0
  345. alysis_code/repo_scan.py +1152 -0
  346. alysis_code/request_estimation.py +296 -0
  347. alysis_code/review_gate.py +617 -0
  348. alysis_code/run_lock.py +1141 -0
  349. alysis_code/run_outcome.py +58 -0
  350. alysis_code/run_provenance.py +774 -0
  351. alysis_code/run_state.py +445 -0
  352. alysis_code/runtime_artifacts.py +116 -0
  353. alysis_code/runtime_context_features.py +78 -0
  354. alysis_code/runtime_kind.py +52 -0
  355. alysis_code/safety/__init__.py +11 -0
  356. alysis_code/safety/mcp_sanitize.py +29 -0
  357. alysis_code/safety/safe_http.py +297 -0
  358. alysis_code/safety/subagent_report.py +184 -0
  359. alysis_code/sandbox_doctor.py +682 -0
  360. alysis_code/sandbox_runner.py +1025 -0
  361. alysis_code/sandbox_settings.py +423 -0
  362. alysis_code/serialized_paths.py +355 -0
  363. alysis_code/server/__init__.py +3 -0
  364. alysis_code/server/app.py +367 -0
  365. alysis_code/server/auth.py +34 -0
  366. alysis_code/server/job_config.py +30 -0
  367. alysis_code/server/settings.py +215 -0
  368. alysis_code/server/store.py +193 -0
  369. alysis_code/server/worker_runner.py +657 -0
  370. alysis_code/service_persistence.py +355 -0
  371. alysis_code/session_artifacts.py +108 -0
  372. alysis_code/session_metrics.py +331 -0
  373. alysis_code/session_store.py +624 -0
  374. alysis_code/skills/README.md +34 -0
  375. alysis_code/skills/__init__.py +104 -0
  376. alysis_code/skills/conventions.py +84 -0
  377. alysis_code/skills/discovery.py +176 -0
  378. alysis_code/skills/eval_models.py +232 -0
  379. alysis_code/skills/eval_runner.py +372 -0
  380. alysis_code/skills/evals.py +1344 -0
  381. alysis_code/skills/install.py +293 -0
  382. alysis_code/skills/loader.py +118 -0
  383. alysis_code/skills/matching.py +103 -0
  384. alysis_code/skills/models.py +71 -0
  385. alysis_code/skills/paths.py +56 -0
  386. alysis_code/skills/prompting.py +500 -0
  387. alysis_code/skills/scaffold.py +142 -0
  388. alysis_code/skills/state.py +441 -0
  389. alysis_code/skills/transactions.py +125 -0
  390. alysis_code/skills/validation.py +304 -0
  391. alysis_code/step_budget.py +238 -0
  392. alysis_code/subagent_labels.py +49 -0
  393. alysis_code/subagents.py +1072 -0
  394. alysis_code/surface/__init__.py +80 -0
  395. alysis_code/surface/base.py +305 -0
  396. alysis_code/surface/console.py +387 -0
  397. alysis_code/surface/events.py +372 -0
  398. alysis_code/surface/hidden_surface.py +529 -0
  399. alysis_code/surface/noop_surface.py +219 -0
  400. alysis_code/surface/rich_surface.py +1555 -0
  401. alysis_code/surface/styles.py +67 -0
  402. alysis_code/surface/theme.py +455 -0
  403. alysis_code/surface/types.py +100 -0
  404. alysis_code/swarm_backend.py +926 -0
  405. alysis_code/swarm_orchestrator.py +4020 -0
  406. alysis_code/swarm_scheduler.py +441 -0
  407. alysis_code/swarm_trace.py +429 -0
  408. alysis_code/swarm_worker.py +2119 -0
  409. alysis_code/swarm_write_guard.py +348 -0
  410. alysis_code/task_dependencies.py +170 -0
  411. alysis_code/task_readiness.py +992 -0
  412. alysis_code/task_scope.py +2148 -0
  413. alysis_code/terminal_manager.py +762 -0
  414. alysis_code/terminal_ownership.py +460 -0
  415. alysis_code/text_normalization.py +30 -0
  416. alysis_code/token_budget.py +97 -0
  417. alysis_code/tools/README.md +34 -0
  418. alysis_code/tools/__init__.py +1 -0
  419. alysis_code/tools/artifacts.py +127 -0
  420. alysis_code/tools/availability.py +188 -0
  421. alysis_code/tools/fs.py +1456 -0
  422. alysis_code/tools/git.py +461 -0
  423. alysis_code/tools/history.py +229 -0
  424. alysis_code/tools/http_timeout.py +78 -0
  425. alysis_code/tools/image_generation.py +552 -0
  426. alysis_code/tools/registry.py +2936 -0
  427. alysis_code/tools/repo_map.py +476 -0
  428. alysis_code/tools/search.py +563 -0
  429. alysis_code/tools/shell.py +135 -0
  430. alysis_code/tools/symbols.py +1350 -0
  431. alysis_code/tools/test_discovery.py +643 -0
  432. alysis_code/tools/web.py +482 -0
  433. alysis_code/tools/web_search.py +2012 -0
  434. alysis_code/tools/web_search_dashscope.py +557 -0
  435. alysis_code/tools/web_search_ddgs.py +221 -0
  436. alysis_code/tools/web_search_provider_adapters.py +1429 -0
  437. alysis_code/tools/web_search_tavily.py +194 -0
  438. alysis_code/updates.py +933 -0
  439. alysis_code/usage_tracker.py +1990 -0
  440. alysis_code/verification_command_analysis.py +1004 -0
  441. alysis_code/verification_contract.py +574 -0
  442. alysis_code/verification_failure_summary.py +273 -0
  443. alysis_code/verification_repair.py +385 -0
  444. alysis_code/verify_gate.py +3129 -0
  445. alysis_code/web_research.py +1872 -0
  446. alysis_code/web_search_adapters.py +66 -0
  447. alysis_code/web_search_policy.py +27 -0
  448. alysis_code/workspace_binding.py +389 -0
  449. alysis_code/workspace_binding_ui.py +408 -0
  450. alysis_code/workspace_context.py +273 -0
  451. alysis_code/workspace_isolation.py +138 -0
  452. alysis_code/workspace_provisioning.py +455 -0
  453. alysis_code-0.13.0.dist-info/METADATA +507 -0
  454. alysis_code-0.13.0.dist-info/RECORD +458 -0
  455. alysis_code-0.13.0.dist-info/WHEEL +4 -0
  456. alysis_code-0.13.0.dist-info/entry_points.txt +3 -0
  457. alysis_code-0.13.0.dist-info/licenses/LICENSE +176 -0
  458. alysis_code-0.13.0.dist-info/licenses/NOTICE +4 -0
@@ -0,0 +1 @@
1
+ """Context planning and request-size diagnostics."""
@@ -0,0 +1,220 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
4
+ import hashlib
5
+ import json
6
+ from dataclasses import dataclass
7
+ from typing import Any
8
+
9
+ from ..token_budget import estimate_tokens
10
+
11
+ DEFAULT_TOOL_SCHEMA_BUDGET_TOKENS = 8_000
12
+ DEFAULT_LARGEST_TOOL_COUNT = 5
13
+ DEFAULT_CUSTOM_MCP_DESCRIPTION_MAX_CHARS = 800
14
+
15
+ CUSTOM_MCP_SCHEMA_FAMILIES = frozenset({"custom", "custom_tool", "mcp", "mcp_tool"})
16
+ MODEL_FACING_SCHEMA_ANNOTATION_KEYS = frozenset(
17
+ {
18
+ "$comment",
19
+ "default",
20
+ "description",
21
+ "example",
22
+ "examples",
23
+ "markdownDescription",
24
+ "title",
25
+ }
26
+ )
27
+ JSON_SCHEMA_NAMED_SCHEMA_MAP_KEYS = frozenset(
28
+ {
29
+ "$defs",
30
+ "definitions",
31
+ "dependentSchemas",
32
+ "patternProperties",
33
+ "properties",
34
+ }
35
+ )
36
+ JSON_SCHEMA_OPAQUE_DATA_KEYS = frozenset(
37
+ {
38
+ "const",
39
+ "default",
40
+ "enum",
41
+ }
42
+ )
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class ToolSchemaBudgetEntry:
47
+ name: str
48
+ token_estimate: int
49
+ family: str
50
+
51
+ def to_payload(self) -> dict[str, Any]:
52
+ return {
53
+ "name": self.name,
54
+ "token_estimate": self.token_estimate,
55
+ "family": self.family,
56
+ }
57
+
58
+ @classmethod
59
+ def from_payload(cls, payload: Any) -> ToolSchemaBudgetEntry | None:
60
+ if not isinstance(payload, dict):
61
+ return None
62
+ name = str(payload.get("name") or "").strip()
63
+ if not name:
64
+ return None
65
+ return cls(
66
+ name=name,
67
+ token_estimate=_as_non_negative_int(payload.get("token_estimate")),
68
+ family=_tool_family(name, payload.get("family")),
69
+ )
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ class ToolSchemaBudgetReport:
74
+ tool_count: int
75
+ total_tokens: int
76
+ budget_tokens: int
77
+ over_budget_tokens: int
78
+ signature: str
79
+ largest_tools: tuple[ToolSchemaBudgetEntry, ...] = ()
80
+
81
+ @property
82
+ def over_budget(self) -> bool:
83
+ return self.over_budget_tokens > 0
84
+
85
+ def to_payload(self) -> dict[str, Any]:
86
+ return {
87
+ "tool_count": self.tool_count,
88
+ "total_tokens": self.total_tokens,
89
+ "budget_tokens": self.budget_tokens,
90
+ "over_budget_tokens": self.over_budget_tokens,
91
+ "over_budget": self.over_budget,
92
+ "signature": self.signature,
93
+ "largest_tools": [entry.to_payload() for entry in self.largest_tools],
94
+ }
95
+
96
+ @classmethod
97
+ def from_payload(cls, payload: Any) -> ToolSchemaBudgetReport | None:
98
+ if not isinstance(payload, dict):
99
+ return None
100
+ signature = str(payload.get("signature") or "").strip()
101
+ entries: list[ToolSchemaBudgetEntry] = []
102
+ raw_entries = payload.get("largest_tools")
103
+ if isinstance(raw_entries, list):
104
+ for raw_entry in raw_entries:
105
+ entry = ToolSchemaBudgetEntry.from_payload(raw_entry)
106
+ if entry is not None:
107
+ entries.append(entry)
108
+ return cls(
109
+ tool_count=_as_non_negative_int(payload.get("tool_count")),
110
+ total_tokens=_as_non_negative_int(payload.get("total_tokens")),
111
+ budget_tokens=_as_non_negative_int(payload.get("budget_tokens")),
112
+ over_budget_tokens=_as_non_negative_int(payload.get("over_budget_tokens")),
113
+ signature=signature,
114
+ largest_tools=tuple(entries),
115
+ )
116
+
117
+
118
+ def analyze_tool_schema_budget(
119
+ tool_list: list[dict[str, Any]] | None,
120
+ *,
121
+ budget_tokens: int = DEFAULT_TOOL_SCHEMA_BUDGET_TOKENS,
122
+ largest_count: int = DEFAULT_LARGEST_TOOL_COUNT,
123
+ ) -> ToolSchemaBudgetReport:
124
+ tools = [tool for tool in (tool_list or []) if isinstance(tool, dict)]
125
+ entries: list[ToolSchemaBudgetEntry] = []
126
+ for index, tool in enumerate(tools, start=1):
127
+ name = _tool_name(tool, fallback=f"tool_{index}")
128
+ entries.append(
129
+ ToolSchemaBudgetEntry(
130
+ name=name,
131
+ token_estimate=_estimate_single_tool_schema_tokens(tool),
132
+ family=_tool_family(name, None),
133
+ )
134
+ )
135
+ total = estimate_tokens(_stable_json(tools)) if tools else 0
136
+ budget = max(0, int(budget_tokens or 0))
137
+ largest_n = max(0, int(largest_count or 0))
138
+ largest_tools = tuple(
139
+ sorted(entries, key=lambda entry: (-entry.token_estimate, entry.name.casefold()))[
140
+ :largest_n
141
+ ]
142
+ )
143
+ return ToolSchemaBudgetReport(
144
+ tool_count=len(tools),
145
+ total_tokens=total,
146
+ budget_tokens=budget,
147
+ over_budget_tokens=max(0, total - budget) if budget > 0 else 0,
148
+ signature=tool_schema_signature(tools),
149
+ largest_tools=largest_tools,
150
+ )
151
+
152
+
153
+ def tool_schema_signature(tool_list: list[dict[str, Any]] | None) -> str:
154
+ payload = _stable_json([tool for tool in (tool_list or []) if isinstance(tool, dict)])
155
+ return hashlib.sha256(payload.encode("utf-8")).hexdigest()[:16]
156
+
157
+
158
+ def compact_custom_mcp_tool_parameters(
159
+ value: Any,
160
+ *,
161
+ _inside_named_schema_map: bool = False,
162
+ ) -> Any:
163
+ """Drop annotation-only JSON Schema prose from custom/MCP model-facing schemas."""
164
+ if isinstance(value, dict):
165
+ compacted: dict[str, Any] = {}
166
+ for key, item in value.items():
167
+ normalized_key = str(key)
168
+ if not _inside_named_schema_map:
169
+ if normalized_key in MODEL_FACING_SCHEMA_ANNOTATION_KEYS:
170
+ continue
171
+ if normalized_key in JSON_SCHEMA_OPAQUE_DATA_KEYS:
172
+ # enum/const/default hold constraint data, not subschemas.
173
+ compacted[key] = copy.deepcopy(item)
174
+ continue
175
+ compacted[key] = compact_custom_mcp_tool_parameters(
176
+ item,
177
+ _inside_named_schema_map=normalized_key in JSON_SCHEMA_NAMED_SCHEMA_MAP_KEYS,
178
+ )
179
+ return compacted
180
+ if isinstance(value, list):
181
+ return [compact_custom_mcp_tool_parameters(item) for item in value]
182
+ return value
183
+
184
+
185
+ def _estimate_single_tool_schema_tokens(tool: dict[str, Any]) -> int:
186
+ return estimate_tokens(_stable_json(tool))
187
+
188
+
189
+ def _stable_json(value: Any) -> str:
190
+ return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
191
+
192
+
193
+ def _tool_name(tool: dict[str, Any], *, fallback: str) -> str:
194
+ function = tool.get("function")
195
+ if isinstance(function, dict):
196
+ name = str(function.get("name") or "").strip()
197
+ if name:
198
+ return name
199
+ name = str(tool.get("name") or "").strip()
200
+ return name or fallback
201
+
202
+
203
+ def _tool_family(name: str, raw_family: Any) -> str:
204
+ family = str(raw_family or "").strip().lower()
205
+ if family:
206
+ return family
207
+ normalized = str(name or "").strip().lower()
208
+ if normalized.startswith("mcp__") or normalized.startswith("mcp_"):
209
+ return "mcp"
210
+ if normalized.startswith("custom__") or normalized.startswith("custom_"):
211
+ return "custom"
212
+ return "builtin"
213
+
214
+
215
+ def _as_non_negative_int(value: Any) -> int:
216
+ try:
217
+ parsed = int(value)
218
+ except (TypeError, ValueError):
219
+ return 0
220
+ return max(0, parsed)
@@ -0,0 +1,282 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import math
5
+ import os
6
+ import threading
7
+ import time
8
+ import warnings
9
+ from dataclasses import dataclass, field
10
+ from datetime import UTC, datetime
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from .error_text import sanitize_error_summary
15
+ from .failure_category import classify_failure_category, extract_status_code
16
+ from .logging_redaction import redact_log_text
17
+
18
+ CRASH_DIAGNOSTIC_SCHEMA_VERSION = 1
19
+
20
+ _PATH_LOCKS_GUARD = threading.Lock()
21
+ _PATH_LOCKS: dict[str, threading.Lock] = {}
22
+
23
+ _ALLOWED_FIELDS = {
24
+ "budget_seconds",
25
+ "checkpoint_fraction",
26
+ "completion_gate_decision",
27
+ "deadline_config_source",
28
+ "deadline",
29
+ "deadline_configured_seconds",
30
+ "deadline_exhausted",
31
+ "deadline_finalization_reason",
32
+ "deadline_finalization_reserve_seconds",
33
+ "deadline_normal_work_remaining_seconds",
34
+ "deadline_phase",
35
+ "deadline_prevented_launch",
36
+ "deadline_remaining_seconds",
37
+ "deadline_start_decision",
38
+ "duration_ms",
39
+ "elapsed_fraction",
40
+ "elapsed_seconds",
41
+ "error_summary",
42
+ "error_type",
43
+ "exit_code",
44
+ "failure_category",
45
+ "grace_seconds",
46
+ "material_edit_count",
47
+ "max_steps",
48
+ "model",
49
+ "operation",
50
+ "provider_status_code",
51
+ "reason",
52
+ "remaining_seconds",
53
+ "runtime_kind",
54
+ "session_source",
55
+ "status",
56
+ "step",
57
+ "steps_attempted",
58
+ "steps_completed",
59
+ # Machine-readable terminal marker. Without this entry the key is silently
60
+ # dropped by the allowlist filter below and a budget stop stays
61
+ # indistinguishable from a crash in the crash log.
62
+ "stop_reason",
63
+ "subagent",
64
+ "subagent_role",
65
+ "subagent_session_id",
66
+ "success",
67
+ "termination_kind",
68
+ "tool_name",
69
+ "usage_counts",
70
+ "verification_attempt_count",
71
+ }
72
+ _NESTED_ALLOWED_FIELDS = {
73
+ "allowed",
74
+ "average_seconds",
75
+ "configured_seconds",
76
+ "count",
77
+ "deadline_monotonic",
78
+ "dispatch_overhead_seconds",
79
+ "duration_observations",
80
+ "elapsed_seconds",
81
+ "enabled",
82
+ "estimated_duration_seconds",
83
+ "exhausted",
84
+ "finalization_directive_sent",
85
+ "finalization_llm_started",
86
+ "finalization_reason",
87
+ "finalization_reserve_seconds",
88
+ "adaptive_retry_llm",
89
+ "compaction_llm",
90
+ "exploration_tool",
91
+ "local_final_summary",
92
+ "main_llm",
93
+ "main_llm_retry",
94
+ "max_seconds",
95
+ "minimum_required_seconds",
96
+ "mutation_tool",
97
+ "normal_work_remaining_seconds",
98
+ "operation",
99
+ "phase",
100
+ "provider_retry_sleep",
101
+ "remaining_seconds",
102
+ "shell_background",
103
+ "shell_tool",
104
+ "source",
105
+ "subagent",
106
+ "tool_dispatch",
107
+ "verification",
108
+ }
109
+
110
+ _HIGH_VALUE_EVENTS = {
111
+ "run_started",
112
+ "terminal_error",
113
+ "deadline_exhausted",
114
+ "progress_checkpoint_failed",
115
+ "run_budget_watchdog_fired",
116
+ "run_finished",
117
+ "turn_finished",
118
+ }
119
+
120
+
121
+ def _lock_for_path(path: Path) -> threading.Lock:
122
+ key = os.fspath(path.resolve())
123
+ with _PATH_LOCKS_GUARD:
124
+ lock = _PATH_LOCKS.get(key)
125
+ if lock is None:
126
+ lock = threading.Lock()
127
+ _PATH_LOCKS[key] = lock
128
+ return lock
129
+
130
+
131
+ def _now_ts() -> str:
132
+ return datetime.now(UTC).isoformat()
133
+
134
+
135
+ def _safe_scalar(value: Any) -> Any:
136
+ if isinstance(value, bool) or value is None:
137
+ return value
138
+ if isinstance(value, int):
139
+ return value
140
+ if isinstance(value, float):
141
+ return round(value, 6) if math.isfinite(value) else None
142
+ if isinstance(value, str):
143
+ return value[:240]
144
+ if isinstance(value, dict):
145
+ return {
146
+ str(key)[:80]: _safe_scalar(item)
147
+ for key, item in value.items()
148
+ if str(key) in _ALLOWED_FIELDS or str(key) in _NESTED_ALLOWED_FIELDS
149
+ }
150
+ if isinstance(value, (list, tuple)):
151
+ return [_safe_scalar(item) for item in list(value)[:20]]
152
+ return str(value)[:120]
153
+
154
+
155
+ @dataclass
156
+ class CrashDiagnosticLogger:
157
+ path: Path | None
158
+ run_id: str
159
+ session_id: str
160
+ runtime_kind: str = ""
161
+ _started_at_monotonic: float = field(default_factory=time.monotonic)
162
+ write_failures: int = 0
163
+
164
+ @classmethod
165
+ def disabled(cls) -> CrashDiagnosticLogger:
166
+ return cls(path=None, run_id="", session_id="", runtime_kind="")
167
+
168
+ @property
169
+ def enabled(self) -> bool:
170
+ return self.path is not None
171
+
172
+ def event(
173
+ self,
174
+ event_type: str,
175
+ payload: dict[str, Any] | None = None,
176
+ *,
177
+ durable: bool = False,
178
+ ) -> None:
179
+ if self.path is None:
180
+ return
181
+ event_type = str(event_type or "").strip()
182
+ if not event_type:
183
+ return
184
+ raw_payload = dict(payload or {})
185
+ safe_payload = {
186
+ key: _safe_scalar(value) for key, value in raw_payload.items() if key in _ALLOWED_FIELDS
187
+ }
188
+ if self.runtime_kind and "runtime_kind" not in safe_payload:
189
+ safe_payload["runtime_kind"] = self.runtime_kind
190
+ event = {
191
+ "schema_version": CRASH_DIAGNOSTIC_SCHEMA_VERSION,
192
+ "event_type": event_type,
193
+ "ts": _now_ts(),
194
+ "monotonic_elapsed_seconds": round(
195
+ max(0.0, time.monotonic() - self._started_at_monotonic),
196
+ 6,
197
+ ),
198
+ "run_id": self.run_id,
199
+ "session_id": self.session_id,
200
+ "payload": safe_payload,
201
+ }
202
+ self._write_line(event, durable=durable or event_type in _HIGH_VALUE_EVENTS)
203
+
204
+ def _write_line(self, event: dict[str, Any], *, durable: bool) -> None:
205
+ assert self.path is not None
206
+ try:
207
+ self.path.parent.mkdir(parents=True, exist_ok=True)
208
+ line = redact_log_text(json.dumps(event, ensure_ascii=True, sort_keys=True) + "\n")
209
+ lock = _lock_for_path(self.path)
210
+ with lock:
211
+ with self.path.open("a", encoding="utf-8") as fh:
212
+ fh.write(line)
213
+ fh.flush()
214
+ if durable:
215
+ os.fsync(fh.fileno())
216
+ except Exception as exc:
217
+ # A broken diagnostic sink must not crash the run, but it must not be
218
+ # silent either: an autonomous fix-loop that "captured nothing" while
219
+ # believing it captured everything is worse than a loud one-time warning.
220
+ self.write_failures += 1
221
+ if self.write_failures == 1:
222
+ warnings.warn(
223
+ f"crash diagnostic write to {self.path} failed "
224
+ f"({type(exc).__name__}: {exc}); subsequent write failures are counted "
225
+ "in write_failures but not re-warned.",
226
+ RuntimeWarning,
227
+ stacklevel=2,
228
+ )
229
+ return
230
+
231
+
232
+ def build_crash_diagnostic_logger(
233
+ *,
234
+ path: str | os.PathLike[str] | None,
235
+ run_id: str,
236
+ session_id: str,
237
+ runtime_kind: str = "",
238
+ ) -> CrashDiagnosticLogger:
239
+ raw = str(path or "").strip()
240
+ if not raw:
241
+ return CrashDiagnosticLogger.disabled()
242
+ return CrashDiagnosticLogger(
243
+ path=Path(raw),
244
+ run_id=run_id,
245
+ session_id=session_id,
246
+ runtime_kind=runtime_kind,
247
+ )
248
+
249
+
250
+ def build_error_event_fields(
251
+ error: BaseException | str | None,
252
+ *,
253
+ operation: str | None = None,
254
+ step: int | None = None,
255
+ ) -> dict[str, Any]:
256
+ """Build the redacted, joinable error block for a terminal/diagnostic event.
257
+
258
+ The block answers the question an autonomous fix-loop actually needs after a
259
+ failed build — *why* did it die — without ever persisting a secret:
260
+
261
+ - ``error_type``: the exception class name (e.g. ``LLMError``),
262
+ - ``error_summary``: the message, secret-redacted and length-bounded via the
263
+ shared :func:`sanitize_error_summary`,
264
+ - ``failure_category``: a real :class:`FailureCategory` (never the legacy
265
+ ``"llm_error"`` literal) so the cause joins across chat/run and Forge artifacts,
266
+ - ``provider_status_code``: the HTTP status when one can be recovered.
267
+
268
+ Safe to call from inside a failure path: it never raises.
269
+ """
270
+ fields: dict[str, Any] = {
271
+ "error_type": type(error).__name__,
272
+ "error_summary": sanitize_error_summary(str(error or "")),
273
+ "failure_category": classify_failure_category(error).value,
274
+ }
275
+ status_code = extract_status_code(error)
276
+ if status_code is not None:
277
+ fields["provider_status_code"] = status_code
278
+ if operation:
279
+ fields["operation"] = str(operation)
280
+ if step is not None:
281
+ fields["step"] = int(step)
282
+ return fields
@@ -0,0 +1,34 @@
1
+ # Custom Tools
2
+
3
+ This package implements Alysis Code's single-file Python custom tools. A custom
4
+ tool is user- or workspace-provided code with a literal manifest and a
5
+ `run(args)` entrypoint.
6
+
7
+ ## Contents
8
+
9
+ - `discovery.py` validates candidate tool files without importing them.
10
+ - `trust.py` records project-tool trust by workspace, relative path, and file
11
+ hash.
12
+ - `session.py` builds the effective custom-tool catalog for a session.
13
+ - `runtime.py` executes trusted tools and applies declared capability checks.
14
+
15
+ ## Scope
16
+
17
+ Project tools are not trusted by default. Editing or moving a trusted project
18
+ tool invalidates trust.
19
+
20
+ Discovery must remain import-free. Candidate code should not run while the host
21
+ is deciding whether the tool is valid or trusted.
22
+
23
+ Capability checks are not a complete sandbox. Treat custom tools as trusted
24
+ code and keep the documentation precise about that boundary.
25
+
26
+ ## Development
27
+
28
+ Manifest, trust, and runtime changes should test valid and rejected tools, plus
29
+ the structured errors users will see.
30
+
31
+ ## See Also
32
+
33
+ - [Custom tools](../../../docs/custom_tools.md)
34
+ - [Security model](../../../docs/security_model.md)
@@ -0,0 +1,43 @@
1
+ from .discovery import (
2
+ CustomToolCapabilities,
3
+ CustomToolDiscoveryResult,
4
+ CustomToolIssue,
5
+ CustomToolSpec,
6
+ discover_custom_tools,
7
+ global_custom_tools_root,
8
+ project_custom_tools_root,
9
+ )
10
+ from .runtime import run_custom_tool
11
+ from .session import (
12
+ CustomToolCatalogEntry,
13
+ CustomToolSessionState,
14
+ build_custom_tool_session_state,
15
+ )
16
+ from .trust import (
17
+ ProjectToolTrustKey,
18
+ ProjectToolTrustState,
19
+ is_project_tool_trusted,
20
+ load_trust_state,
21
+ trust_project_tool,
22
+ untrust_project_tool,
23
+ )
24
+
25
+ __all__ = [
26
+ "CustomToolCatalogEntry",
27
+ "CustomToolCapabilities",
28
+ "CustomToolDiscoveryResult",
29
+ "CustomToolIssue",
30
+ "CustomToolSessionState",
31
+ "CustomToolSpec",
32
+ "ProjectToolTrustKey",
33
+ "ProjectToolTrustState",
34
+ "build_custom_tool_session_state",
35
+ "discover_custom_tools",
36
+ "global_custom_tools_root",
37
+ "is_project_tool_trusted",
38
+ "load_trust_state",
39
+ "project_custom_tools_root",
40
+ "run_custom_tool",
41
+ "trust_project_tool",
42
+ "untrust_project_tool",
43
+ ]