celltype-cli 0.1.3__tar.gz → 0.2.1__tar.gz

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 (274) hide show
  1. celltype_cli-0.2.1/.git +1 -0
  2. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.gitignore +1 -0
  3. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/PKG-INFO +20 -4
  4. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/README.md +7 -2
  5. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/install.sh +19 -11
  6. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/pyproject.toml +15 -2
  7. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/__init__.py +1 -1
  8. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/config.py +9 -2
  9. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/doctor.py +53 -0
  10. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/mcp_server.py +105 -20
  11. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/runner.py +6 -1
  12. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/session.py +1 -1
  13. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/system_prompt.py +17 -0
  14. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/cli.py +712 -15
  15. celltype_cli-0.2.1/src/ct/cloud/__init__.py +3 -0
  16. celltype_cli-0.2.1/src/ct/cloud/auth.py +197 -0
  17. celltype_cli-0.2.1/src/ct/cloud/client.py +227 -0
  18. celltype_cli-0.2.1/src/ct/cloud/local_runner.py +274 -0
  19. celltype_cli-0.2.1/src/ct/cloud/router.py +332 -0
  20. celltype_cli-0.2.1/src/ct/cloud/structure_inputs.py +50 -0
  21. celltype_cli-0.2.1/src/ct/cloud/tool_entrypoint.py +56 -0
  22. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/models/llm.py +1 -1
  23. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/__init__.py +72 -2
  24. celltype_cli-0.2.1/src/ct/tools/_container_tools.py +97 -0
  25. celltype_cli-0.2.1/src/ct/tools/_schema_contract.py +44 -0
  26. celltype_cli-0.2.1/src/ct/tools/alphafold2/Dockerfile +47 -0
  27. celltype_cli-0.2.1/src/ct/tools/alphafold2/implementation.py +297 -0
  28. celltype_cli-0.2.1/src/ct/tools/alphafold2/patch_jackhmmer.py +11 -0
  29. celltype_cli-0.2.1/src/ct/tools/alphafold2/tool.yaml +70 -0
  30. celltype_cli-0.2.1/src/ct/tools/alphafold2/tool_entrypoint.py +27 -0
  31. celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/Dockerfile +43 -0
  32. celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/implementation.py +389 -0
  33. celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/tool.yaml +83 -0
  34. celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/tool_entrypoint.py +27 -0
  35. celltype_cli-0.2.1/src/ct/tools/boltz2/Dockerfile +20 -0
  36. celltype_cli-0.2.1/src/ct/tools/boltz2/implementation.py +104 -0
  37. celltype_cli-0.2.1/src/ct/tools/boltz2/tool.yaml +52 -0
  38. celltype_cli-0.2.1/src/ct/tools/boltz2/tool_entrypoint.py +27 -0
  39. celltype_cli-0.2.1/src/ct/tools/diffdock/Dockerfile +26 -0
  40. celltype_cli-0.2.1/src/ct/tools/diffdock/implementation.py +225 -0
  41. celltype_cli-0.2.1/src/ct/tools/diffdock/tool.yaml +53 -0
  42. celltype_cli-0.2.1/src/ct/tools/diffdock/tool_entrypoint.py +27 -0
  43. celltype_cli-0.2.1/src/ct/tools/esm2/Dockerfile +17 -0
  44. celltype_cli-0.2.1/src/ct/tools/esm2/implementation.py +55 -0
  45. celltype_cli-0.2.1/src/ct/tools/esm2/tool.yaml +41 -0
  46. celltype_cli-0.2.1/src/ct/tools/esm2/tool_entrypoint.py +27 -0
  47. celltype_cli-0.2.1/src/ct/tools/esmfold/Dockerfile +18 -0
  48. celltype_cli-0.2.1/src/ct/tools/esmfold/implementation.py +98 -0
  49. celltype_cli-0.2.1/src/ct/tools/esmfold/tool.yaml +36 -0
  50. celltype_cli-0.2.1/src/ct/tools/esmfold/tool_entrypoint.py +27 -0
  51. celltype_cli-0.2.1/src/ct/tools/evo2/Dockerfile +18 -0
  52. celltype_cli-0.2.1/src/ct/tools/evo2/implementation.py +174 -0
  53. celltype_cli-0.2.1/src/ct/tools/evo2/tool.yaml +69 -0
  54. celltype_cli-0.2.1/src/ct/tools/evo2/tool_entrypoint.py +27 -0
  55. celltype_cli-0.2.1/src/ct/tools/genmol/Dockerfile +13 -0
  56. celltype_cli-0.2.1/src/ct/tools/genmol/implementation.py +101 -0
  57. celltype_cli-0.2.1/src/ct/tools/genmol/tool.yaml +71 -0
  58. celltype_cli-0.2.1/src/ct/tools/genmol/tool_entrypoint.py +27 -0
  59. celltype_cli-0.2.1/src/ct/tools/molmim/Dockerfile +13 -0
  60. celltype_cli-0.2.1/src/ct/tools/molmim/implementation.py +97 -0
  61. celltype_cli-0.2.1/src/ct/tools/molmim/tool.yaml +66 -0
  62. celltype_cli-0.2.1/src/ct/tools/molmim/tool_entrypoint.py +27 -0
  63. celltype_cli-0.2.1/src/ct/tools/msa-search/Dockerfile +23 -0
  64. celltype_cli-0.2.1/src/ct/tools/msa-search/implementation.py +428 -0
  65. celltype_cli-0.2.1/src/ct/tools/msa-search/tool.yaml +59 -0
  66. celltype_cli-0.2.1/src/ct/tools/msa-search/tool_entrypoint.py +27 -0
  67. celltype_cli-0.2.1/src/ct/tools/openfold2/Dockerfile +47 -0
  68. celltype_cli-0.2.1/src/ct/tools/openfold2/implementation.py +508 -0
  69. celltype_cli-0.2.1/src/ct/tools/openfold2/tool.yaml +103 -0
  70. celltype_cli-0.2.1/src/ct/tools/openfold2/tool_entrypoint.py +27 -0
  71. celltype_cli-0.2.1/src/ct/tools/openfold3/Dockerfile +49 -0
  72. celltype_cli-0.2.1/src/ct/tools/openfold3/implementation.py +545 -0
  73. celltype_cli-0.2.1/src/ct/tools/openfold3/tool.yaml +94 -0
  74. celltype_cli-0.2.1/src/ct/tools/openfold3/tool_entrypoint.py +27 -0
  75. celltype_cli-0.2.1/src/ct/tools/proteinmpnn/Dockerfile +24 -0
  76. celltype_cli-0.2.1/src/ct/tools/proteinmpnn/implementation.py +97 -0
  77. celltype_cli-0.2.1/src/ct/tools/proteinmpnn/tool.yaml +50 -0
  78. celltype_cli-0.2.1/src/ct/tools/proteinmpnn/tool_entrypoint.py +27 -0
  79. celltype_cli-0.2.1/src/ct/tools/rfdiffusion/Dockerfile +33 -0
  80. celltype_cli-0.2.1/src/ct/tools/rfdiffusion/implementation.py +425 -0
  81. celltype_cli-0.2.1/src/ct/tools/rfdiffusion/tool.yaml +64 -0
  82. celltype_cli-0.2.1/src/ct/tools/rfdiffusion/tool_entrypoint.py +27 -0
  83. celltype_cli-0.2.1/src/ct/tools/tool_entrypoint.py +27 -0
  84. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/terminal.py +7 -1
  85. celltype_cli-0.2.1/src/ct/update_checker.py +111 -0
  86. celltype_cli-0.2.1/tests/e2e/__init__.py +0 -0
  87. celltype_cli-0.2.1/tests/e2e/kras_g12c.fasta +6 -0
  88. celltype_cli-0.2.1/tests/e2e/sotorasib.smi +1 -0
  89. celltype_cli-0.2.1/tests/e2e/test_e2e_cloud.py +241 -0
  90. celltype_cli-0.2.1/tests/test_billing.py +133 -0
  91. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_cli.py +16 -0
  92. celltype_cli-0.2.1/tests/test_cloud_auth.py +151 -0
  93. celltype_cli-0.2.1/tests/test_cloud_client.py +170 -0
  94. celltype_cli-0.2.1/tests/test_compute_router.py +332 -0
  95. celltype_cli-0.2.1/tests/test_e2e_local_gpu.py +260 -0
  96. celltype_cli-0.2.1/tests/test_extensibility.py +182 -0
  97. celltype_cli-0.2.1/tests/test_fallback_routing.py +172 -0
  98. celltype_cli-0.2.1/tests/test_gpu_registry.py +213 -0
  99. celltype_cli-0.2.1/tests/test_local_runner.py +235 -0
  100. celltype_cli-0.2.1/tests/test_modal_generation.py +143 -0
  101. celltype_cli-0.2.1/tests/test_observability.py +118 -0
  102. celltype_cli-0.2.1/tests/test_security_mitigations.py +220 -0
  103. celltype_cli-0.2.1/tests/test_setup_gpu.py +114 -0
  104. celltype_cli-0.2.1/tests/test_stripe_integration.py +324 -0
  105. celltype_cli-0.1.3/.claude/settings.local.json +0 -96
  106. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/apply.md +0 -0
  107. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/archive.md +0 -0
  108. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/bulk-archive.md +0 -0
  109. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/continue.md +0 -0
  110. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/explore.md +0 -0
  111. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/ff.md +0 -0
  112. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/new.md +0 -0
  113. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/onboard.md +0 -0
  114. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/sync.md +0 -0
  115. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/verify.md +0 -0
  116. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-apply-change/SKILL.md +0 -0
  117. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-archive-change/SKILL.md +0 -0
  118. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -0
  119. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-continue-change/SKILL.md +0 -0
  120. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-explore/SKILL.md +0 -0
  121. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-ff-change/SKILL.md +0 -0
  122. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-new-change/SKILL.md +0 -0
  123. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-onboard/SKILL.md +0 -0
  124. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-sync-specs/SKILL.md +0 -0
  125. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-verify-change/SKILL.md +0 -0
  126. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.dockerignore +0 -0
  127. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.github/workflows/ci.yml +0 -0
  128. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/CLAUDE.md +0 -0
  129. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/Dockerfile +0 -0
  130. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/Dockerfile.api +0 -0
  131. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/LICENSE +0 -0
  132. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/assets/bixbench_benchmark.png +0 -0
  133. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/assets/ct2.gif +0 -0
  134. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/docker-compose.yml +0 -0
  135. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/openspec/config.yaml +0 -0
  136. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/scripts/prepare_datasets.py +0 -0
  137. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/scripts/prepare_l1000.py +0 -0
  138. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/settings.json +0 -0
  139. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/__init__.py +0 -0
  140. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/case_studies.py +0 -0
  141. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/knowledge.py +0 -0
  142. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/loop.py +0 -0
  143. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/orchestrator.py +0 -0
  144. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/sandbox.py +0 -0
  145. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/trace_store.py +0 -0
  146. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/trajectory.py +0 -0
  147. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/types.py +0 -0
  148. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/workflows.py +0 -0
  149. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/__init__.py +0 -0
  150. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/app.py +0 -0
  151. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/config.py +0 -0
  152. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/engine.py +0 -0
  153. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/__init__.py +0 -0
  154. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/compute_providers.json +0 -0
  155. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/cro_database.json +0 -0
  156. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/downloader.py +0 -0
  157. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/loaders.py +0 -0
  158. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/__init__.py +0 -0
  159. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/benchmarks.py +0 -0
  160. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/governance.py +0 -0
  161. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/ingest.py +0 -0
  162. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/reasoning.py +0 -0
  163. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/schema_monitor.py +0 -0
  164. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/substrate.py +0 -0
  165. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/models/__init__.py +0 -0
  166. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/_compound_resolver.py +0 -0
  167. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/biomarker.py +0 -0
  168. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/cellxgene.py +0 -0
  169. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/chemistry.py +0 -0
  170. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/claude.py +0 -0
  171. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/clinical.py +0 -0
  172. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/clue.py +0 -0
  173. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/code.py +0 -0
  174. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/combination.py +0 -0
  175. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/compute.py +0 -0
  176. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/cro.py +0 -0
  177. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/data_api.py +0 -0
  178. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/design.py +0 -0
  179. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/dna.py +0 -0
  180. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/experiment.py +0 -0
  181. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/expression.py +0 -0
  182. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/files.py +0 -0
  183. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/genomics.py +0 -0
  184. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/http_client.py +0 -0
  185. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/imaging.py +0 -0
  186. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/intel.py +0 -0
  187. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/literature.py +0 -0
  188. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/network.py +0 -0
  189. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/notification.py +0 -0
  190. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/omics.py +0 -0
  191. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/ops.py +0 -0
  192. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/parity.py +0 -0
  193. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/pk.py +0 -0
  194. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/protein.py +0 -0
  195. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/regulatory.py +0 -0
  196. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/remote_data.py +0 -0
  197. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/report.py +0 -0
  198. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/repurposing.py +0 -0
  199. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/safety.py +0 -0
  200. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/shell.py +0 -0
  201. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/singlecell.py +0 -0
  202. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/statistics.py +0 -0
  203. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/structure.py +0 -0
  204. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/target.py +0 -0
  205. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/translational.py +0 -0
  206. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/viability.py +0 -0
  207. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/__init__.py +0 -0
  208. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/markdown.py +0 -0
  209. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/status.py +0 -0
  210. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/suggestions.py +0 -0
  211. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/traces.py +0 -0
  212. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/__init__.py +0 -0
  213. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/conftest.py +0 -0
  214. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/fixtures/plan_snapshot.txt +0 -0
  215. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/fixtures/trace_snapshot.txt +0 -0
  216. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_api_smoke.py +0 -0
  217. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_cellxgene.py +0 -0
  218. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_chemistry_new.py +0 -0
  219. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_claude.py +0 -0
  220. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_clue.py +0 -0
  221. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_code.py +0 -0
  222. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_compute.py +0 -0
  223. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_config.py +0 -0
  224. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_cro.py +0 -0
  225. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_data_api.py +0 -0
  226. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_data_api_service.py +0 -0
  227. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_design.py +0 -0
  228. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_dna.py +0 -0
  229. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_doctor.py +0 -0
  230. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_downloader.py +0 -0
  231. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_engine.py +0 -0
  232. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_experiment.py +0 -0
  233. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_files.py +0 -0
  234. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_future_backends_todo.py +0 -0
  235. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_html_report.py +0 -0
  236. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_http_client.py +0 -0
  237. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_imaging.py +0 -0
  238. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_benchmarks.py +0 -0
  239. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_governance.py +0 -0
  240. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_ingest.py +0 -0
  241. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_reasoning.py +0 -0
  242. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_schema_monitor.py +0 -0
  243. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_substrate.py +0 -0
  244. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_knowledge.py +0 -0
  245. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_llm.py +0 -0
  246. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_mention_completer.py +0 -0
  247. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_network.py +0 -0
  248. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_notebook.py +0 -0
  249. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_notification.py +0 -0
  250. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_omics.py +0 -0
  251. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_ops.py +0 -0
  252. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_parity_tools.py +0 -0
  253. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_parkinsons_toolchain_smoke.py +0 -0
  254. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_patent_search.py +0 -0
  255. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_plan_display.py +0 -0
  256. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_protein.py +0 -0
  257. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_registry.py +0 -0
  258. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_remote_data.py +0 -0
  259. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_repurposing.py +0 -0
  260. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_sandbox.py +0 -0
  261. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_sdk_streaming.py +0 -0
  262. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_session.py +0 -0
  263. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_shell.py +0 -0
  264. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_singlecell.py +0 -0
  265. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_status.py +0 -0
  266. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_structure.py +0 -0
  267. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_target.py +0 -0
  268. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_terminal.py +0 -0
  269. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_terminal_integration.py +0 -0
  270. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_tools.py +0 -0
  271. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_trace_store.py +0 -0
  272. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_traces.py +0 -0
  273. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_trajectory.py +0 -0
  274. {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_workflows.py +0 -0
@@ -0,0 +1 @@
1
+ gitdir: ../.git/modules/cli
@@ -52,3 +52,4 @@ busco_downloads/
52
52
 
53
53
 
54
54
 
55
+ .vercel
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: celltype-cli
3
- Version: 0.1.3
3
+ Version: 0.2.1
4
4
  Summary: CellType CLI — An autonomous agent for drug discovery research
5
5
  Author: CellType Inc.
6
- License-Expression: MIT
6
+ License: MIT
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.10
9
9
  Requires-Dist: anthropic>=0.74.0
@@ -16,7 +16,9 @@ Requires-Dist: numpy>=1.24
16
16
  Requires-Dist: openai>=1.0
17
17
  Requires-Dist: pandas>=2.0
18
18
  Requires-Dist: prompt-toolkit>=3.0
19
+ Requires-Dist: pydantic>=2.0
19
20
  Requires-Dist: python-dotenv>=1.0
21
+ Requires-Dist: pyyaml>=6.0
20
22
  Requires-Dist: rich>=13.0
21
23
  Requires-Dist: scipy>=1.10
22
24
  Requires-Dist: typer>=0.12
@@ -33,6 +35,12 @@ Requires-Dist: seaborn>=0.13; extra == 'all'
33
35
  Requires-Dist: tiledbsoma>=1.0; extra == 'all'
34
36
  Requires-Dist: torch>=2.0; extra == 'all'
35
37
  Requires-Dist: transformers>=4.40; extra == 'all'
38
+ Provides-Extra: alpha
39
+ Requires-Dist: duckdb>=1.0; extra == 'alpha'
40
+ Requires-Dist: fastapi>=0.100; extra == 'alpha'
41
+ Requires-Dist: jinja2>=3.1; extra == 'alpha'
42
+ Requires-Dist: pydantic>=2.0; extra == 'alpha'
43
+ Requires-Dist: uvicorn[standard]>=0.20; extra == 'alpha'
36
44
  Provides-Extra: analysis
37
45
  Requires-Dist: scikit-learn>=1.3; extra == 'analysis'
38
46
  Requires-Dist: seaborn>=0.13; extra == 'analysis'
@@ -44,6 +52,9 @@ Provides-Extra: biology
44
52
  Requires-Dist: biopython>=1.81; extra == 'biology'
45
53
  Provides-Extra: chemistry
46
54
  Requires-Dist: rdkit>=2023.03; extra == 'chemistry'
55
+ Provides-Extra: cloud
56
+ Requires-Dist: modal>=1.0; extra == 'cloud'
57
+ Requires-Dist: pyjwt>=2.0; extra == 'cloud'
47
58
  Provides-Extra: dev
48
59
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
49
60
  Requires-Dist: pytest>=8.0; extra == 'dev'
@@ -64,6 +75,11 @@ Description-Content-Type: text/markdown
64
75
 
65
76
  # celltype-cli
66
77
 
78
+ > **v0.2.0 is out** — Offload GPU-accelerated tools to CellType Cloud with no additional setup. ESMFold, Boltz-2, RFdiffusion, ProteinMPNN, and more. Update now:
79
+ > ```bash
80
+ > curl -fsSL https://raw.githubusercontent.com/celltype/celltype-agent/main/install.sh | bash
81
+ > ```
82
+
67
83
  An autonomous agent for drug discovery research. Like Claude Code, but for biology.
68
84
 
69
85
  Ask questions in natural language. celltype-cli plans the analysis, selects the right tools, executes them, validates results, and returns data-backed conclusions.
@@ -99,10 +115,10 @@ CellType CLI achieves **90% accuracy** on [BixBench-Verified-50](https://hugging
99
115
  ### Quick install
100
116
 
101
117
  ```bash
102
- curl -fsSL https://raw.githubusercontent.com/celltype/cli/main/install.sh | bash
118
+ curl -fsSL https://raw.githubusercontent.com/celltype/celltype-agent/main/install.sh | bash
103
119
  ```
104
120
 
105
- Detects Python 3.10+, installs via `pipx` or `pip`, and launches an interactive setup wizard.
121
+ Detects Python 3.10+, installs the latest `celltype-cli` release from PyPI via `uv`, `pipx`, or `pip`, and launches the interactive setup wizard.
106
122
 
107
123
  ### Manual install
108
124
 
@@ -1,5 +1,10 @@
1
1
  # celltype-cli
2
2
 
3
+ > **v0.2.0 is out** — Offload GPU-accelerated tools to CellType Cloud with no additional setup. ESMFold, Boltz-2, RFdiffusion, ProteinMPNN, and more. Update now:
4
+ > ```bash
5
+ > curl -fsSL https://raw.githubusercontent.com/celltype/celltype-agent/main/install.sh | bash
6
+ > ```
7
+
3
8
  An autonomous agent for drug discovery research. Like Claude Code, but for biology.
4
9
 
5
10
  Ask questions in natural language. celltype-cli plans the analysis, selects the right tools, executes them, validates results, and returns data-backed conclusions.
@@ -35,10 +40,10 @@ CellType CLI achieves **90% accuracy** on [BixBench-Verified-50](https://hugging
35
40
  ### Quick install
36
41
 
37
42
  ```bash
38
- curl -fsSL https://raw.githubusercontent.com/celltype/cli/main/install.sh | bash
43
+ curl -fsSL https://raw.githubusercontent.com/celltype/celltype-agent/main/install.sh | bash
39
44
  ```
40
45
 
41
- Detects Python 3.10+, installs via `pipx` or `pip`, and launches an interactive setup wizard.
46
+ Detects Python 3.10+, installs the latest `celltype-cli` release from PyPI via `uv`, `pipx`, or `pip`, and launches the interactive setup wizard.
42
47
 
43
48
  ### Manual install
44
49
 
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env bash
2
2
  # celltype-cli — One-liner installer
3
- # Usage: curl -fsSL https://raw.githubusercontent.com/celltype/cli/main/install.sh | bash
3
+ # Usage: curl -fsSL https://raw.githubusercontent.com/celltype/celltype-agent/main/install.sh | bash
4
4
  set -euo pipefail
5
5
 
6
6
  PACKAGE="celltype-cli"
7
- REPO_URL="git+https://github.com/celltype/cli.git"
8
7
  MIN_PYTHON="3.10"
9
8
 
10
9
  # ── Helpers ────────────────────────────────────────────────────
@@ -46,15 +45,15 @@ esac
46
45
 
47
46
  # ── Install package ────────────────────────────────────────────
48
47
 
49
- INSTALL_SPEC="${PACKAGE} @ ${REPO_URL}"
48
+ INSTALL_SPEC="${PACKAGE}"
50
49
 
51
50
  if command -v uv >/dev/null 2>&1; then
52
- info "Installing ${PACKAGE} via uv..."
53
- uv tool install "$INSTALL_SPEC" || uv tool install --force "$INSTALL_SPEC"
51
+ info "Installing latest ${PACKAGE} from PyPI via uv..."
52
+ uv tool install "$INSTALL_SPEC" || uv tool install --upgrade "$INSTALL_SPEC" || uv tool install --force "$INSTALL_SPEC"
54
53
  ok "Installed with uv"
55
54
  elif command -v pipx >/dev/null 2>&1; then
56
- info "Installing ${PACKAGE} via pipx..."
57
- pipx install "$REPO_URL" || pipx install --force "$REPO_URL"
55
+ info "Installing latest ${PACKAGE} from PyPI via pipx..."
56
+ pipx install "$INSTALL_SPEC" || pipx upgrade "$PACKAGE" || pipx install --force "$INSTALL_SPEC"
58
57
  ok "Installed with pipx"
59
58
  else
60
59
  warn "uv/pipx not found — falling back to pip install --user"
@@ -83,7 +82,16 @@ ok "ct $(ct --version 2>/dev/null || echo '(installed)')"
83
82
 
84
83
  # ── Run setup wizard ───────────────────────────────────────────
85
84
 
86
- info ""
87
- info "Running setup wizard..."
88
- info ""
89
- ct setup
85
+ if "$PYTHON" -c 'import os; fd = os.open("/dev/tty", os.O_RDONLY); os.close(fd)' 2>/dev/null; then
86
+ info ""
87
+ info "Running setup wizard..."
88
+ info ""
89
+ # When installed via `curl ... | bash`, stdin is the download pipe rather
90
+ # than the user's keyboard. Reattach setup to the controlling terminal so
91
+ # interactive prompts and masked input work normally.
92
+ ct setup < /dev/tty
93
+ else
94
+ warn ""
95
+ warn "Skipping interactive setup because no terminal is available."
96
+ warn "Run: ct setup"
97
+ fi
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "celltype-cli"
7
- version = "0.1.3"
7
+ version = "0.2.1"
8
8
  description = "CellType CLI — An autonomous agent for drug discovery research"
9
9
  readme = "README.md"
10
- license = "MIT"
10
+ license = {text = "MIT"}
11
11
  requires-python = ">=3.10"
12
12
  authors = [
13
13
  { name = "CellType Inc." },
@@ -28,6 +28,8 @@ dependencies = [
28
28
  "python-dotenv>=1.0",
29
29
  "markdown>=3.5",
30
30
  "nbformat>=5.7",
31
+ "pyyaml>=6.0",
32
+ "pydantic>=2.0",
31
33
  ]
32
34
 
33
35
  [project.optional-dependencies]
@@ -61,6 +63,17 @@ api = [
61
63
  "uvicorn[standard]>=0.20",
62
64
  "duckdb>=1.0",
63
65
  ]
66
+ alpha = [
67
+ "fastapi>=0.100",
68
+ "uvicorn[standard]>=0.20",
69
+ "duckdb>=1.0",
70
+ "jinja2>=3.1",
71
+ "pydantic>=2.0",
72
+ ]
73
+ cloud = [
74
+ "modal>=1.0",
75
+ "pyjwt>=2.0",
76
+ ]
64
77
  all = [
65
78
  "rdkit>=2023.03",
66
79
  "biopython>=1.81",
@@ -1,3 +1,3 @@
1
1
  """celltype-cli: An autonomous agent for drug discovery research."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.2.0"
@@ -29,11 +29,10 @@ logger = logging.getLogger("ct.config")
29
29
 
30
30
  DEFAULTS = {
31
31
  "llm.provider": "anthropic",
32
- "llm.model": "claude-sonnet-4-5-20250929",
32
+ "llm.model": "claude-opus-4-6",
33
33
  "llm.api_key": None,
34
34
  "llm.openai_api_key": None,
35
35
  "llm.temperature": 0.1,
36
-
37
36
  "data.base": str(CONFIG_DIR / "data"),
38
37
  "data.depmap": None,
39
38
  "data.prism": None,
@@ -67,6 +66,14 @@ DEFAULTS = {
67
66
  "compute.lambda_api_key": None,
68
67
  "compute.runpod_api_key": None,
69
68
  "compute.default_provider": "lambda",
69
+ "compute.mode": "cloud",
70
+
71
+ "cloud.endpoint": "https://api.celltype.com",
72
+ "cloud.dashboard_url": "https://cloud.celltype.com",
73
+
74
+ "gpu.name": None,
75
+ "gpu.vram_mb": None,
76
+ "gpu.setup_completed": False,
70
77
 
71
78
  "sandbox.timeout": 30,
72
79
  "sandbox.output_dir": str(Path.cwd() / "outputs"),
@@ -340,6 +340,59 @@ def run_checks(config: Config | None = None, session=None) -> list[DoctorCheck]:
340
340
  )
341
341
  )
342
342
 
343
+ # GPU compute readiness
344
+ compute_mode = str(cfg.get("compute.mode", "cloud")).lower()
345
+ if compute_mode == "cloud":
346
+ try:
347
+ from ct.cloud.auth import is_logged_in
348
+ if is_logged_in():
349
+ checks.append(DoctorCheck(
350
+ name="gpu_compute",
351
+ status="ok",
352
+ detail="compute.mode=cloud, logged in to CellType Cloud",
353
+ ))
354
+ else:
355
+ checks.append(DoctorCheck(
356
+ name="gpu_compute",
357
+ status="warn",
358
+ detail="compute.mode=cloud but not logged in. Run `ct login`.",
359
+ ))
360
+ except Exception:
361
+ checks.append(DoctorCheck(
362
+ name="gpu_compute",
363
+ status="warn",
364
+ detail="compute.mode=cloud, could not check login status",
365
+ ))
366
+ elif compute_mode == "local":
367
+ try:
368
+ from ct.cloud.router import _detect_local_gpu_info
369
+ gpus = _detect_local_gpu_info()
370
+ if gpus:
371
+ best = max(gpus, key=lambda g: g.vram_mb)
372
+ checks.append(DoctorCheck(
373
+ name="gpu_compute",
374
+ status="ok",
375
+ detail=f"compute.mode=local, GPU: {best.name} ({best.vram_gb}GB)",
376
+ ))
377
+ else:
378
+ checks.append(DoctorCheck(
379
+ name="gpu_compute",
380
+ status="error",
381
+ detail="compute.mode=local but no GPU detected. Run `ct setup-gpu`.",
382
+ ))
383
+ except Exception:
384
+ checks.append(DoctorCheck(
385
+ name="gpu_compute",
386
+ status="warn",
387
+ detail="compute.mode=local, could not detect GPU",
388
+ ))
389
+ else:
390
+ checks.append(DoctorCheck(
391
+ name="gpu_compute",
392
+ status="ok",
393
+ detail="compute.mode=auto (will detect at runtime)",
394
+ ))
395
+
343
396
  return checks
344
397
 
345
398
 
@@ -71,6 +71,14 @@ _PY_TYPE_MAP = {
71
71
  }
72
72
 
73
73
 
74
+ def _is_json_schema(parameters: dict) -> bool:
75
+ return (
76
+ isinstance(parameters, dict)
77
+ and parameters.get("type") == "object"
78
+ and isinstance(parameters.get("properties"), dict)
79
+ )
80
+
81
+
74
82
  def _params_to_json_schema(parameters: dict) -> dict:
75
83
  """Convert a ct tool parameters dict to a JSON Schema object.
76
84
 
@@ -81,6 +89,9 @@ def _params_to_json_schema(parameters: dict) -> dict:
81
89
  if not parameters:
82
90
  return {"type": "object", "properties": {}}
83
91
 
92
+ if _is_json_schema(parameters):
93
+ return parameters
94
+
84
95
  properties = {}
85
96
  for name, desc in parameters.items():
86
97
  # Extract type hint from description if present (e.g., "gene name (str)")
@@ -110,29 +121,43 @@ def _make_tool_handler(tool_obj, session):
110
121
  call_args["_session"] = session
111
122
  call_args["_prior_results"] = {}
112
123
 
113
- # Coerce string values to numeric types when they look like numbers.
114
- # MCP sends all parameters as strings, but tools often expect int/float.
115
- for key, val in list(call_args.items()):
116
- if key.startswith("_"):
117
- continue
118
- if isinstance(val, str):
119
- # Try int first, then float
120
- try:
121
- call_args[key] = int(val)
124
+ # Legacy flat ct manifests describe every parameter as a string, so keep
125
+ # backwards-compatible coercion there. Structured JSON Schema tools should
126
+ # preserve the exact payload emitted by the SDK.
127
+ if not _is_json_schema(getattr(tool_obj, "parameters", {})):
128
+ for key, val in list(call_args.items()):
129
+ if key.startswith("_"):
122
130
  continue
123
- except ValueError:
124
- pass
125
- try:
126
- call_args[key] = float(val)
127
- continue
128
- except ValueError:
129
- pass
130
- # Boolean coercion
131
- if val.lower() in ("true", "false"):
132
- call_args[key] = val.lower() == "true"
131
+ if isinstance(val, str):
132
+ try:
133
+ call_args[key] = int(val)
134
+ continue
135
+ except ValueError:
136
+ pass
137
+ try:
138
+ call_args[key] = float(val)
139
+ continue
140
+ except ValueError:
141
+ pass
142
+ if val.lower() in ("true", "false"):
143
+ call_args[key] = val.lower() == "true"
133
144
 
134
145
  try:
135
- result = await asyncio.to_thread(tool_obj.run, **call_args)
146
+ # Route GPU tools through compute router
147
+ if getattr(tool_obj, "requires_gpu", False) or getattr(tool_obj, "cpu_only", False):
148
+ from ct.cloud.router import ComputeRouter
149
+ router = ComputeRouter(config=getattr(session, "config", None))
150
+ result = await asyncio.to_thread(router.route, tool_obj, **call_args)
151
+
152
+ # Handle "needs_user_prompt" — the router couldn't run locally
153
+ # and needs the user to decide about cloud fallback.
154
+ # We prompt here on the main thread where input() works.
155
+ if isinstance(result, dict) and result.get("needs_user_prompt"):
156
+ result = await _prompt_cloud_fallback(
157
+ router, tool_obj, result, call_args, session,
158
+ )
159
+ else:
160
+ result = await asyncio.to_thread(tool_obj.run, **call_args)
136
161
  text = _format_tool_result(result)
137
162
  except Exception as e:
138
163
  logger.warning("Tool %s raised: %s", tool_obj.name, e)
@@ -147,6 +172,66 @@ def _make_tool_handler(tool_obj, session):
147
172
  return handler
148
173
 
149
174
 
175
+ async def _prompt_cloud_fallback(router, tool_obj, prompt_result, call_args, session):
176
+ """Prompt the user on the main thread about switching to CellType Cloud.
177
+
178
+ Called when compute.mode=local but the tool can't run locally.
179
+ Runs on the event loop (main thread) so input() works correctly.
180
+
181
+ Options:
182
+ y — run this tool on CellType Cloud (one-time)
183
+ n — skip this tool
184
+ n! — skip and don't ask again for this session
185
+ """
186
+ from rich.console import Console
187
+ console = getattr(session, "console", None) or Console()
188
+
189
+ # Stop the spinner so it doesn't interfere with the prompt
190
+ spinner = getattr(session, "_active_spinner", None)
191
+ if spinner is not None:
192
+ spinner.stop()
193
+ session._active_spinner = None
194
+
195
+ msg = prompt_result.get("prompt_message", "GPU tool cannot run locally.")
196
+
197
+ console.print(f"\n [yellow]{msg}[/yellow]")
198
+
199
+ try:
200
+ answer = input(
201
+ " Use CellType Cloud for this tool call?\n"
202
+ " [y] yes [y!] yes for all (switch to cloud mode) [n] no (skip this tool call): "
203
+ ).strip().lower()
204
+ except (EOFError, KeyboardInterrupt):
205
+ answer = "n"
206
+
207
+ if answer in ("y", "yes"):
208
+ # One-time cloud dispatch for this tool call
209
+ result = await asyncio.to_thread(router.route_cloud_for_tool, tool_obj, **call_args)
210
+ return result
211
+ elif answer in ("y!", "yes!"):
212
+ # Switch to cloud mode permanently — no more prompts
213
+ try:
214
+ from ct.agent.config import Config
215
+ cfg = Config.load()
216
+ cfg.set("compute.mode", "cloud")
217
+ cfg.save()
218
+ console.print(" [green]compute.mode switched to cloud[/green]")
219
+ except Exception:
220
+ pass
221
+ result = await asyncio.to_thread(router.route_cloud_for_tool, tool_obj, **call_args)
222
+ return result
223
+ else:
224
+ # n / anything else — skip this tool call
225
+ return {
226
+ "summary": (
227
+ f"[Skipped] {tool_obj.name} — {msg} "
228
+ "User chose to skip this tool call."
229
+ ),
230
+ "skipped": True,
231
+ "reason": "user_skipped",
232
+ }
233
+
234
+
150
235
  # ---------------------------------------------------------------------------
151
236
  # run_python sandbox tool
152
237
  # ---------------------------------------------------------------------------
@@ -101,6 +101,8 @@ async def process_messages(
101
101
  thinking_status = None
102
102
  if runner is not None:
103
103
  runner._active_spinner = None
104
+ if hasattr(runner, "session"):
105
+ runner.session._active_spinner = None
104
106
 
105
107
  text = block.text or ""
106
108
  full_text.append(text)
@@ -130,6 +132,9 @@ async def process_messages(
130
132
  thinking_status.start_async_refresh()
131
133
  if runner is not None:
132
134
  runner._active_spinner = thinking_status
135
+ # Also store on session so MCP prompt can stop it
136
+ if runner is not None and hasattr(runner, "session"):
137
+ runner.session._active_spinner = thinking_status
133
138
  except ImportError:
134
139
  pass
135
140
 
@@ -337,7 +342,7 @@ class AgentRunner:
337
342
  )
338
343
 
339
344
  # ----- Configure Agent SDK -----
340
- model = config.get("llm.model") or "claude-sonnet-4-5-20250929"
345
+ model = config.get("llm.model") or "claude-opus-4-6"
341
346
  max_turns = int(config.get("agent.max_sdk_turns", 30))
342
347
 
343
348
  allowed_tools = [f"mcp__ct-tools__{name}" for name in tool_names]
@@ -54,7 +54,7 @@ class Session:
54
54
  """Return the current model name."""
55
55
  if self._llm:
56
56
  return self._llm.model
57
- return self.config.get("llm.model") or "claude-sonnet-4-5-20250929"
57
+ return self.config.get("llm.model") or "claude-opus-4-6"
58
58
 
59
59
  def log(self, message: str):
60
60
  """Log to scratchpad (for debugging/transparency)."""
@@ -69,6 +69,20 @@ BANNED PHRASES — never write these:
69
69
  If tools failed, pivot to answering from your knowledge instead.
70
70
  """
71
71
 
72
+ _STRUCTURE_INPUT_GUIDANCE = """\
73
+
74
+ ## Structure File Inputs
75
+
76
+ For tools that accept `target_pdb`, `backbone_pdb`, or `protein_pdb`, you may
77
+ provide either:
78
+ - inline PDB/mmCIF text, or
79
+ - a local filesystem path to a `.pdb`, `.cif`, `.mmcif`, or `.ent` file.
80
+
81
+ If the structure is already saved locally, prefer passing the file path instead
82
+ of pasting the full structure text. The local runner and CellType Cloud client
83
+ will inline the file contents automatically before dispatch.
84
+ """
85
+
72
86
 
73
87
  # ---------------------------------------------------------------------------
74
88
  # Builder
@@ -167,6 +181,9 @@ def build_system_prompt(
167
181
  # 8. Synthesis instructions
168
182
  parts.append(_SYNTHESIS_INSTRUCTIONS)
169
183
 
184
+ # 8b. Structure input guidance
185
+ parts.append(_STRUCTURE_INPUT_GUIDANCE)
186
+
170
187
  # 9. Dynamic data context
171
188
  if data_context:
172
189
  parts.append("\n## Data Context\n")