celltype-cli 0.1.2__tar.gz → 0.2.0__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 (268) hide show
  1. celltype_cli-0.2.0/.git +1 -0
  2. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.gitignore +1 -0
  3. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/PKG-INFO +20 -4
  4. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/README.md +6 -1
  5. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/install.sh +11 -8
  6. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/pyproject.toml +16 -3
  7. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/__init__.py +1 -1
  8. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/config.py +19 -2
  9. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/doctor.py +59 -5
  10. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/mcp_server.py +75 -1
  11. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/runner.py +24 -1
  12. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/sandbox.py +5 -2
  13. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/session.py +1 -1
  14. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/system_prompt.py +17 -0
  15. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/cli.py +674 -13
  16. celltype_cli-0.2.0/src/ct/cloud/__init__.py +3 -0
  17. celltype_cli-0.2.0/src/ct/cloud/auth.py +197 -0
  18. celltype_cli-0.2.0/src/ct/cloud/client.py +226 -0
  19. celltype_cli-0.2.0/src/ct/cloud/image_builder.py +152 -0
  20. celltype_cli-0.2.0/src/ct/cloud/local_runner.py +276 -0
  21. celltype_cli-0.2.0/src/ct/cloud/manifest.py +178 -0
  22. celltype_cli-0.2.0/src/ct/cloud/router.py +332 -0
  23. celltype_cli-0.2.0/src/ct/cloud/structure_inputs.py +49 -0
  24. celltype_cli-0.2.0/src/ct/cloud/tool_entrypoint.py +56 -0
  25. celltype_cli-0.2.0/src/ct/cloud/weight_downloader.py +217 -0
  26. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/models/llm.py +7 -4
  27. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/__init__.py +57 -1
  28. celltype_cli-0.2.0/src/ct/tools/_container_tools.py +97 -0
  29. celltype_cli-0.2.0/src/ct/tools/alphafold2/Dockerfile +47 -0
  30. celltype_cli-0.2.0/src/ct/tools/alphafold2/implementation.py +200 -0
  31. celltype_cli-0.2.0/src/ct/tools/alphafold2/patch_jackhmmer.py +11 -0
  32. celltype_cli-0.2.0/src/ct/tools/alphafold2/tool.yaml +17 -0
  33. celltype_cli-0.2.0/src/ct/tools/alphafold2-multimer/Dockerfile +43 -0
  34. celltype_cli-0.2.0/src/ct/tools/alphafold2-multimer/implementation.py +184 -0
  35. celltype_cli-0.2.0/src/ct/tools/alphafold2-multimer/tool.yaml +17 -0
  36. celltype_cli-0.2.0/src/ct/tools/boltz2/Dockerfile +20 -0
  37. celltype_cli-0.2.0/src/ct/tools/boltz2/implementation.py +104 -0
  38. celltype_cli-0.2.0/src/ct/tools/boltz2/tool.yaml +19 -0
  39. celltype_cli-0.2.0/src/ct/tools/diffdock/Dockerfile +26 -0
  40. celltype_cli-0.2.0/src/ct/tools/diffdock/implementation.py +225 -0
  41. celltype_cli-0.2.0/src/ct/tools/diffdock/tool.yaml +20 -0
  42. celltype_cli-0.2.0/src/ct/tools/esm2/Dockerfile +17 -0
  43. celltype_cli-0.2.0/src/ct/tools/esm2/implementation.py +55 -0
  44. celltype_cli-0.2.0/src/ct/tools/esm2/tool.yaml +18 -0
  45. celltype_cli-0.2.0/src/ct/tools/esmfold/Dockerfile +18 -0
  46. celltype_cli-0.2.0/src/ct/tools/esmfold/implementation.py +98 -0
  47. celltype_cli-0.2.0/src/ct/tools/esmfold/tool.yaml +18 -0
  48. celltype_cli-0.2.0/src/ct/tools/evo2/Dockerfile +18 -0
  49. celltype_cli-0.2.0/src/ct/tools/evo2/implementation.py +63 -0
  50. celltype_cli-0.2.0/src/ct/tools/evo2/tool.yaml +19 -0
  51. celltype_cli-0.2.0/src/ct/tools/evo2-protein-design/Dockerfile +18 -0
  52. celltype_cli-0.2.0/src/ct/tools/evo2-protein-design/implementation.py +64 -0
  53. celltype_cli-0.2.0/src/ct/tools/evo2-protein-design/tool.yaml +19 -0
  54. celltype_cli-0.2.0/src/ct/tools/genmol/Dockerfile +13 -0
  55. celltype_cli-0.2.0/src/ct/tools/genmol/implementation.py +101 -0
  56. celltype_cli-0.2.0/src/ct/tools/genmol/tool.yaml +20 -0
  57. celltype_cli-0.2.0/src/ct/tools/molmim/Dockerfile +13 -0
  58. celltype_cli-0.2.0/src/ct/tools/molmim/implementation.py +97 -0
  59. celltype_cli-0.2.0/src/ct/tools/molmim/tool.yaml +19 -0
  60. celltype_cli-0.2.0/src/ct/tools/msa-search/Dockerfile +17 -0
  61. celltype_cli-0.2.0/src/ct/tools/msa-search/implementation.py +138 -0
  62. celltype_cli-0.2.0/src/ct/tools/msa-search/tool.yaml +18 -0
  63. celltype_cli-0.2.0/src/ct/tools/openfold2/Dockerfile +47 -0
  64. celltype_cli-0.2.0/src/ct/tools/openfold2/implementation.py +200 -0
  65. celltype_cli-0.2.0/src/ct/tools/openfold2/tool.yaml +17 -0
  66. celltype_cli-0.2.0/src/ct/tools/openfold3/Dockerfile +49 -0
  67. celltype_cli-0.2.0/src/ct/tools/openfold3/implementation.py +222 -0
  68. celltype_cli-0.2.0/src/ct/tools/openfold3/tool.yaml +19 -0
  69. celltype_cli-0.2.0/src/ct/tools/proteinmpnn/Dockerfile +24 -0
  70. celltype_cli-0.2.0/src/ct/tools/proteinmpnn/implementation.py +97 -0
  71. celltype_cli-0.2.0/src/ct/tools/proteinmpnn/tool.yaml +18 -0
  72. celltype_cli-0.2.0/src/ct/tools/rfdiffusion/Dockerfile +33 -0
  73. celltype_cli-0.2.0/src/ct/tools/rfdiffusion/implementation.py +151 -0
  74. celltype_cli-0.2.0/src/ct/tools/rfdiffusion/tool.yaml +19 -0
  75. celltype_cli-0.2.0/src/ct/tools/tool_entrypoint.py +27 -0
  76. celltype_cli-0.2.0/src/ct/update_checker.py +111 -0
  77. celltype_cli-0.2.0/tests/e2e/__init__.py +0 -0
  78. celltype_cli-0.2.0/tests/e2e/kras_g12c.fasta +6 -0
  79. celltype_cli-0.2.0/tests/e2e/sotorasib.smi +1 -0
  80. celltype_cli-0.2.0/tests/e2e/test_e2e_cloud.py +241 -0
  81. celltype_cli-0.2.0/tests/test_billing.py +133 -0
  82. celltype_cli-0.2.0/tests/test_cloud_auth.py +151 -0
  83. celltype_cli-0.2.0/tests/test_cloud_client.py +170 -0
  84. celltype_cli-0.2.0/tests/test_compute_router.py +332 -0
  85. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_config.py +21 -1
  86. celltype_cli-0.2.0/tests/test_e2e_local_gpu.py +260 -0
  87. celltype_cli-0.2.0/tests/test_extensibility.py +182 -0
  88. celltype_cli-0.2.0/tests/test_fallback_routing.py +172 -0
  89. celltype_cli-0.2.0/tests/test_gpu_registry.py +213 -0
  90. celltype_cli-0.2.0/tests/test_image_builder.py +132 -0
  91. celltype_cli-0.2.0/tests/test_local_runner.py +235 -0
  92. celltype_cli-0.2.0/tests/test_manifest.py +224 -0
  93. celltype_cli-0.2.0/tests/test_modal_generation.py +143 -0
  94. celltype_cli-0.2.0/tests/test_observability.py +118 -0
  95. celltype_cli-0.2.0/tests/test_security_mitigations.py +220 -0
  96. celltype_cli-0.2.0/tests/test_setup_gpu.py +114 -0
  97. celltype_cli-0.2.0/tests/test_stripe_integration.py +324 -0
  98. celltype_cli-0.2.0/tests/test_weight_management.py +138 -0
  99. celltype_cli-0.1.2/.claude/settings.local.json +0 -96
  100. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/apply.md +0 -0
  101. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/archive.md +0 -0
  102. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/bulk-archive.md +0 -0
  103. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/continue.md +0 -0
  104. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/explore.md +0 -0
  105. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/ff.md +0 -0
  106. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/new.md +0 -0
  107. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/onboard.md +0 -0
  108. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/sync.md +0 -0
  109. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/commands/opsx/verify.md +0 -0
  110. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-apply-change/SKILL.md +0 -0
  111. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-archive-change/SKILL.md +0 -0
  112. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -0
  113. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-continue-change/SKILL.md +0 -0
  114. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-explore/SKILL.md +0 -0
  115. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-ff-change/SKILL.md +0 -0
  116. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-new-change/SKILL.md +0 -0
  117. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-onboard/SKILL.md +0 -0
  118. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-sync-specs/SKILL.md +0 -0
  119. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.claude/skills/openspec-verify-change/SKILL.md +0 -0
  120. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.dockerignore +0 -0
  121. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/.github/workflows/ci.yml +0 -0
  122. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/CLAUDE.md +0 -0
  123. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/Dockerfile +0 -0
  124. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/Dockerfile.api +0 -0
  125. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/LICENSE +0 -0
  126. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/assets/bixbench_benchmark.png +0 -0
  127. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/assets/ct2.gif +0 -0
  128. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/docker-compose.yml +0 -0
  129. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/openspec/config.yaml +0 -0
  130. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/scripts/prepare_datasets.py +0 -0
  131. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/scripts/prepare_l1000.py +0 -0
  132. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/settings.json +0 -0
  133. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/__init__.py +0 -0
  134. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/case_studies.py +0 -0
  135. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/knowledge.py +0 -0
  136. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/loop.py +0 -0
  137. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/orchestrator.py +0 -0
  138. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/trace_store.py +0 -0
  139. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/trajectory.py +0 -0
  140. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/types.py +0 -0
  141. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/agent/workflows.py +0 -0
  142. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/api/__init__.py +0 -0
  143. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/api/app.py +0 -0
  144. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/api/config.py +0 -0
  145. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/api/engine.py +0 -0
  146. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/data/__init__.py +0 -0
  147. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/data/compute_providers.json +0 -0
  148. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/data/cro_database.json +0 -0
  149. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/data/downloader.py +0 -0
  150. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/data/loaders.py +0 -0
  151. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/__init__.py +0 -0
  152. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/benchmarks.py +0 -0
  153. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/governance.py +0 -0
  154. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/ingest.py +0 -0
  155. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/reasoning.py +0 -0
  156. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/schema_monitor.py +0 -0
  157. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/kb/substrate.py +0 -0
  158. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/models/__init__.py +0 -0
  159. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/_compound_resolver.py +0 -0
  160. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/biomarker.py +0 -0
  161. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/cellxgene.py +0 -0
  162. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/chemistry.py +0 -0
  163. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/claude.py +0 -0
  164. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/clinical.py +0 -0
  165. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/clue.py +0 -0
  166. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/code.py +0 -0
  167. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/combination.py +0 -0
  168. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/compute.py +0 -0
  169. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/cro.py +0 -0
  170. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/data_api.py +0 -0
  171. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/design.py +0 -0
  172. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/dna.py +0 -0
  173. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/experiment.py +0 -0
  174. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/expression.py +0 -0
  175. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/files.py +0 -0
  176. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/genomics.py +0 -0
  177. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/http_client.py +0 -0
  178. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/imaging.py +0 -0
  179. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/intel.py +0 -0
  180. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/literature.py +0 -0
  181. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/network.py +0 -0
  182. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/notification.py +0 -0
  183. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/omics.py +0 -0
  184. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/ops.py +0 -0
  185. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/parity.py +0 -0
  186. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/pk.py +0 -0
  187. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/protein.py +0 -0
  188. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/regulatory.py +0 -0
  189. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/remote_data.py +0 -0
  190. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/report.py +0 -0
  191. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/repurposing.py +0 -0
  192. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/safety.py +0 -0
  193. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/shell.py +0 -0
  194. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/singlecell.py +0 -0
  195. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/statistics.py +0 -0
  196. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/structure.py +0 -0
  197. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/target.py +0 -0
  198. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/translational.py +0 -0
  199. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/tools/viability.py +0 -0
  200. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/ui/__init__.py +0 -0
  201. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/ui/markdown.py +0 -0
  202. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/ui/status.py +0 -0
  203. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/ui/suggestions.py +0 -0
  204. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/ui/terminal.py +0 -0
  205. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/src/ct/ui/traces.py +0 -0
  206. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/__init__.py +0 -0
  207. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/conftest.py +0 -0
  208. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/fixtures/plan_snapshot.txt +0 -0
  209. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/fixtures/trace_snapshot.txt +0 -0
  210. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_api_smoke.py +0 -0
  211. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_cellxgene.py +0 -0
  212. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_chemistry_new.py +0 -0
  213. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_claude.py +0 -0
  214. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_cli.py +0 -0
  215. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_clue.py +0 -0
  216. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_code.py +0 -0
  217. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_compute.py +0 -0
  218. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_cro.py +0 -0
  219. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_data_api.py +0 -0
  220. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_data_api_service.py +0 -0
  221. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_design.py +0 -0
  222. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_dna.py +0 -0
  223. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_doctor.py +0 -0
  224. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_downloader.py +0 -0
  225. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_engine.py +0 -0
  226. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_experiment.py +0 -0
  227. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_files.py +0 -0
  228. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_future_backends_todo.py +0 -0
  229. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_html_report.py +0 -0
  230. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_http_client.py +0 -0
  231. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_imaging.py +0 -0
  232. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_kb_benchmarks.py +0 -0
  233. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_kb_governance.py +0 -0
  234. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_kb_ingest.py +0 -0
  235. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_kb_reasoning.py +0 -0
  236. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_kb_schema_monitor.py +0 -0
  237. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_kb_substrate.py +0 -0
  238. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_knowledge.py +0 -0
  239. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_llm.py +0 -0
  240. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_mention_completer.py +0 -0
  241. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_network.py +0 -0
  242. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_notebook.py +0 -0
  243. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_notification.py +0 -0
  244. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_omics.py +0 -0
  245. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_ops.py +0 -0
  246. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_parity_tools.py +0 -0
  247. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_parkinsons_toolchain_smoke.py +0 -0
  248. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_patent_search.py +0 -0
  249. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_plan_display.py +0 -0
  250. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_protein.py +0 -0
  251. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_registry.py +0 -0
  252. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_remote_data.py +0 -0
  253. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_repurposing.py +0 -0
  254. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_sandbox.py +0 -0
  255. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_sdk_streaming.py +0 -0
  256. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_session.py +0 -0
  257. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_shell.py +0 -0
  258. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_singlecell.py +0 -0
  259. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_status.py +0 -0
  260. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_structure.py +0 -0
  261. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_target.py +0 -0
  262. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_terminal.py +0 -0
  263. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_terminal_integration.py +0 -0
  264. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_tools.py +0 -0
  265. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_trace_store.py +0 -0
  266. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_traces.py +0 -0
  267. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/tests/test_trajectory.py +0 -0
  268. {celltype_cli-0.1.2 → celltype_cli-0.2.0}/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,21 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: celltype-cli
3
- Version: 0.1.2
3
+ Version: 0.2.0
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
- Requires-Dist: anthropic>=0.40
9
+ Requires-Dist: anthropic>=0.74.0
10
10
  Requires-Dist: claude-agent-sdk>=0.1
11
11
  Requires-Dist: httpx>=0.27
12
12
  Requires-Dist: markdown>=3.5
13
+ Requires-Dist: matplotlib>=3.7
13
14
  Requires-Dist: nbformat>=5.7
14
15
  Requires-Dist: numpy>=1.24
15
16
  Requires-Dist: openai>=1.0
16
17
  Requires-Dist: pandas>=2.0
17
18
  Requires-Dist: prompt-toolkit>=3.0
18
19
  Requires-Dist: python-dotenv>=1.0
20
+ Requires-Dist: pyyaml>=6.0
19
21
  Requires-Dist: rich>=13.0
20
22
  Requires-Dist: scipy>=1.10
21
23
  Requires-Dist: typer>=0.12
@@ -32,6 +34,12 @@ Requires-Dist: seaborn>=0.13; extra == 'all'
32
34
  Requires-Dist: tiledbsoma>=1.0; extra == 'all'
33
35
  Requires-Dist: torch>=2.0; extra == 'all'
34
36
  Requires-Dist: transformers>=4.40; extra == 'all'
37
+ Provides-Extra: alpha
38
+ Requires-Dist: duckdb>=1.0; extra == 'alpha'
39
+ Requires-Dist: fastapi>=0.100; extra == 'alpha'
40
+ Requires-Dist: jinja2>=3.1; extra == 'alpha'
41
+ Requires-Dist: pydantic>=2.0; extra == 'alpha'
42
+ Requires-Dist: uvicorn[standard]>=0.20; extra == 'alpha'
35
43
  Provides-Extra: analysis
36
44
  Requires-Dist: scikit-learn>=1.3; extra == 'analysis'
37
45
  Requires-Dist: seaborn>=0.13; extra == 'analysis'
@@ -43,6 +51,9 @@ Provides-Extra: biology
43
51
  Requires-Dist: biopython>=1.81; extra == 'biology'
44
52
  Provides-Extra: chemistry
45
53
  Requires-Dist: rdkit>=2023.03; extra == 'chemistry'
54
+ Provides-Extra: cloud
55
+ Requires-Dist: modal>=1.0; extra == 'cloud'
56
+ Requires-Dist: pyjwt>=2.0; extra == 'cloud'
46
57
  Provides-Extra: dev
47
58
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
48
59
  Requires-Dist: pytest>=8.0; extra == 'dev'
@@ -63,6 +74,11 @@ Description-Content-Type: text/markdown
63
74
 
64
75
  # celltype-cli
65
76
 
77
+ > **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:
78
+ > ```bash
79
+ > pip install --upgrade celltype-cli
80
+ > ```
81
+
66
82
  An autonomous agent for drug discovery research. Like Claude Code, but for biology.
67
83
 
68
84
  Ask questions in natural language. celltype-cli plans the analysis, selects the right tools, executes them, validates results, and returns data-backed conclusions.
@@ -71,7 +87,7 @@ Ask questions in natural language. celltype-cli plans the analysis, selects the
71
87
 
72
88
  ## Benchmark
73
89
 
74
- CellType CLI achieves **90% accuracy** on [BixBench-Verified-50](https://github.com/bixbench/bixbench), outperforming all existing agentic systems for computational biology.
90
+ CellType CLI achieves **90% accuracy** on [BixBench-Verified-50](https://huggingface.co/datasets/phylobio/BixBench-Verified-50), outperforming all existing agentic systems for computational biology.
75
91
 
76
92
  ![BixBench Benchmark Results](assets/bixbench_benchmark.png)
77
93
 
@@ -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
+ > pip install --upgrade celltype-cli
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.
@@ -8,7 +13,7 @@ Ask questions in natural language. celltype-cli plans the analysis, selects the
8
13
 
9
14
  ## Benchmark
10
15
 
11
- CellType CLI achieves **90% accuracy** on [BixBench-Verified-50](https://github.com/bixbench/bixbench), outperforming all existing agentic systems for computational biology.
16
+ CellType CLI achieves **90% accuracy** on [BixBench-Verified-50](https://huggingface.co/datasets/phylobio/BixBench-Verified-50), outperforming all existing agentic systems for computational biology.
12
17
 
13
18
  ![BixBench Benchmark Results](assets/bixbench_benchmark.png)
14
19
 
@@ -4,6 +4,7 @@
4
4
  set -euo pipefail
5
5
 
6
6
  PACKAGE="celltype-cli"
7
+ REPO_URL="git+https://github.com/celltype/cli.git"
7
8
  MIN_PYTHON="3.10"
8
9
 
9
10
  # ── Helpers ────────────────────────────────────────────────────
@@ -45,17 +46,19 @@ esac
45
46
 
46
47
  # ── Install package ────────────────────────────────────────────
47
48
 
48
- if command -v pipx >/dev/null 2>&1; then
49
- info "Installing ${PACKAGE} via pipx..."
50
- pipx install "$PACKAGE" || pipx upgrade "$PACKAGE"
51
- ok "Installed with pipx"
52
- elif command -v uv >/dev/null 2>&1; then
49
+ INSTALL_SPEC="${PACKAGE} @ ${REPO_URL}"
50
+
51
+ if command -v uv >/dev/null 2>&1; then
53
52
  info "Installing ${PACKAGE} via uv..."
54
- uv tool install "$PACKAGE" || uv tool upgrade "$PACKAGE"
53
+ uv tool install "$INSTALL_SPEC" || uv tool install --force "$INSTALL_SPEC"
55
54
  ok "Installed with uv"
55
+ 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"
58
+ ok "Installed with pipx"
56
59
  else
57
- warn "pipx/uv not found — falling back to pip install --user"
58
- "$PYTHON" -m pip install --user --upgrade "$PACKAGE"
60
+ warn "uv/pipx not found — falling back to pip install --user"
61
+ "$PYTHON" -m pip install --user --upgrade "$INSTALL_SPEC"
59
62
  ok "Installed with pip"
60
63
 
61
64
  # Check if user bin is on PATH
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "celltype-cli"
7
- version = "0.1.2"
7
+ version = "0.2.0"
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." },
@@ -17,16 +17,18 @@ dependencies = [
17
17
  "typer>=0.12",
18
18
  "rich>=13.0",
19
19
  "prompt-toolkit>=3.0",
20
- "anthropic>=0.40",
20
+ "anthropic>=0.74.0",
21
21
  "openai>=1.0",
22
22
  "claude-agent-sdk>=0.1",
23
23
  "httpx>=0.27",
24
24
  "pandas>=2.0",
25
25
  "numpy>=1.24",
26
26
  "scipy>=1.10",
27
+ "matplotlib>=3.7",
27
28
  "python-dotenv>=1.0",
28
29
  "markdown>=3.5",
29
30
  "nbformat>=5.7",
31
+ "pyyaml>=6.0",
30
32
  ]
31
33
 
32
34
  [project.optional-dependencies]
@@ -60,6 +62,17 @@ api = [
60
62
  "uvicorn[standard]>=0.20",
61
63
  "duckdb>=1.0",
62
64
  ]
65
+ alpha = [
66
+ "fastapi>=0.100",
67
+ "uvicorn[standard]>=0.20",
68
+ "duckdb>=1.0",
69
+ "jinja2>=3.1",
70
+ "pydantic>=2.0",
71
+ ]
72
+ cloud = [
73
+ "modal>=1.0",
74
+ "pyjwt>=2.0",
75
+ ]
63
76
  all = [
64
77
  "rdkit>=2023.03",
65
78
  "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,7 +29,7 @@ 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,
@@ -67,6 +67,14 @@ DEFAULTS = {
67
67
  "compute.lambda_api_key": None,
68
68
  "compute.runpod_api_key": None,
69
69
  "compute.default_provider": "lambda",
70
+ "compute.mode": "cloud",
71
+
72
+ "cloud.endpoint": "https://api.celltype.com",
73
+ "cloud.dashboard_url": "https://cloud.celltype.com",
74
+
75
+ "gpu.name": None,
76
+ "gpu.vram_mb": None,
77
+ "gpu.setup_completed": False,
70
78
 
71
79
  "sandbox.timeout": 30,
72
80
  "sandbox.output_dir": str(Path.cwd() / "outputs"),
@@ -456,6 +464,13 @@ class Config:
456
464
  if self.llm_api_key(provider):
457
465
  return None
458
466
 
467
+ # Azure AI Foundry: Foundry-specific env vars are valid Anthropic auth
468
+ if provider == "anthropic" and (
469
+ os.environ.get("ANTHROPIC_FOUNDRY_API_KEY")
470
+ or os.environ.get("ANTHROPIC_FOUNDRY_RESOURCE")
471
+ ):
472
+ return None
473
+
459
474
  if provider == "openai":
460
475
  return (
461
476
  "OpenAI API key not configured. Set OPENAI_API_KEY or run:\n"
@@ -464,7 +479,9 @@ class Config:
464
479
 
465
480
  return (
466
481
  "Anthropic API key not configured. Set ANTHROPIC_API_KEY or run:\n"
467
- " ct config set llm.api_key <key>"
482
+ " ct config set llm.api_key <key>\n"
483
+ "For Azure AI Foundry: set ANTHROPIC_FOUNDRY_API_KEY and "
484
+ "ANTHROPIC_FOUNDRY_RESOURCE"
468
485
  )
469
486
 
470
487
  def keys_table(self) -> Table:
@@ -6,6 +6,7 @@ Used by `ct doctor` and interactive `/doctor` to surface actionable setup issues
6
6
 
7
7
  from dataclasses import dataclass
8
8
  import logging
9
+ import os
9
10
  from pathlib import Path
10
11
 
11
12
  from rich.table import Table
@@ -67,12 +68,12 @@ def run_checks(config: Config | None = None, session=None) -> list[DoctorCheck]:
67
68
  if llm_issue:
68
69
  checks.append(DoctorCheck(name="llm", status="error", detail=llm_issue))
69
70
  else:
71
+ if os.environ.get("ANTHROPIC_FOUNDRY_API_KEY") or os.environ.get("ANTHROPIC_FOUNDRY_RESOURCE"):
72
+ detail = f"provider=anthropic (Azure Foundry), model={model}"
73
+ else:
74
+ detail = f"provider={provider}, model={model}"
70
75
  checks.append(
71
- DoctorCheck(
72
- name="llm",
73
- status="ok",
74
- detail=f"provider={provider}, model={model}",
75
- )
76
+ DoctorCheck(name="llm", status="ok", detail=detail)
76
77
  )
77
78
 
78
79
  # 3) Output directory availability
@@ -339,6 +340,59 @@ def run_checks(config: Config | None = None, session=None) -> list[DoctorCheck]:
339
340
  )
340
341
  )
341
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
+
342
396
  return checks
343
397
 
344
398
 
@@ -132,7 +132,21 @@ def _make_tool_handler(tool_obj, session):
132
132
  call_args[key] = val.lower() == "true"
133
133
 
134
134
  try:
135
- result = await asyncio.to_thread(tool_obj.run, **call_args)
135
+ # Route GPU tools through compute router
136
+ if getattr(tool_obj, "requires_gpu", False):
137
+ from ct.cloud.router import ComputeRouter
138
+ router = ComputeRouter(config=getattr(session, "config", None))
139
+ result = await asyncio.to_thread(router.route, tool_obj, **call_args)
140
+
141
+ # Handle "needs_user_prompt" — the router couldn't run locally
142
+ # and needs the user to decide about cloud fallback.
143
+ # We prompt here on the main thread where input() works.
144
+ if isinstance(result, dict) and result.get("needs_user_prompt"):
145
+ result = await _prompt_cloud_fallback(
146
+ router, tool_obj, result, call_args, session,
147
+ )
148
+ else:
149
+ result = await asyncio.to_thread(tool_obj.run, **call_args)
136
150
  text = _format_tool_result(result)
137
151
  except Exception as e:
138
152
  logger.warning("Tool %s raised: %s", tool_obj.name, e)
@@ -147,6 +161,66 @@ def _make_tool_handler(tool_obj, session):
147
161
  return handler
148
162
 
149
163
 
164
+ async def _prompt_cloud_fallback(router, tool_obj, prompt_result, call_args, session):
165
+ """Prompt the user on the main thread about switching to CellType Cloud.
166
+
167
+ Called when compute.mode=local but the tool can't run locally.
168
+ Runs on the event loop (main thread) so input() works correctly.
169
+
170
+ Options:
171
+ y — run this tool on CellType Cloud (one-time)
172
+ n — skip this tool
173
+ n! — skip and don't ask again for this session
174
+ """
175
+ from rich.console import Console
176
+ console = getattr(session, "console", None) or Console()
177
+
178
+ # Stop the spinner so it doesn't interfere with the prompt
179
+ spinner = getattr(session, "_active_spinner", None)
180
+ if spinner is not None:
181
+ spinner.stop()
182
+ session._active_spinner = None
183
+
184
+ msg = prompt_result.get("prompt_message", "GPU tool cannot run locally.")
185
+
186
+ console.print(f"\n [yellow]{msg}[/yellow]")
187
+
188
+ try:
189
+ answer = input(
190
+ " Use CellType Cloud for this tool call?\n"
191
+ " [y] yes [y!] yes for all (switch to cloud mode) [n] no (skip this tool call): "
192
+ ).strip().lower()
193
+ except (EOFError, KeyboardInterrupt):
194
+ answer = "n"
195
+
196
+ if answer in ("y", "yes"):
197
+ # One-time cloud dispatch for this tool call
198
+ result = await asyncio.to_thread(router.route_cloud_for_tool, tool_obj, **call_args)
199
+ return result
200
+ elif answer in ("y!", "yes!"):
201
+ # Switch to cloud mode permanently — no more prompts
202
+ try:
203
+ from ct.agent.config import Config
204
+ cfg = Config.load()
205
+ cfg.set("compute.mode", "cloud")
206
+ cfg.save()
207
+ console.print(" [green]compute.mode switched to cloud[/green]")
208
+ except Exception:
209
+ pass
210
+ result = await asyncio.to_thread(router.route_cloud_for_tool, tool_obj, **call_args)
211
+ return result
212
+ else:
213
+ # n / anything else — skip this tool call
214
+ return {
215
+ "summary": (
216
+ f"[Skipped] {tool_obj.name} — {msg} "
217
+ "User chose to skip this tool call."
218
+ ),
219
+ "skipped": True,
220
+ "reason": "user_skipped",
221
+ }
222
+
223
+
150
224
  # ---------------------------------------------------------------------------
151
225
  # run_python sandbox tool
152
226
  # ---------------------------------------------------------------------------
@@ -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]
@@ -357,6 +362,24 @@ class AgentRunner:
357
362
  # Suppress warnings in SDK subprocess (matplotlib, pydeseq2, numpy, etc.)
358
363
  clean_env["PYTHONWARNINGS"] = "ignore"
359
364
 
365
+ # Enable Foundry mode for Agent SDK subprocess if Foundry env vars present
366
+ if any(clean_env.get(v) for v in (
367
+ "ANTHROPIC_FOUNDRY_API_KEY",
368
+ "ANTHROPIC_FOUNDRY_RESOURCE",
369
+ "ANTHROPIC_FOUNDRY_BASE_URL",
370
+ )):
371
+ clean_env["CLAUDE_CODE_USE_FOUNDRY"] = "1"
372
+ # Pin model names for Foundry deployments
373
+ clean_env.setdefault(
374
+ "ANTHROPIC_DEFAULT_SONNET_MODEL", model
375
+ )
376
+ clean_env.setdefault(
377
+ "ANTHROPIC_DEFAULT_OPUS_MODEL", model
378
+ )
379
+ clean_env.setdefault(
380
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL", model
381
+ )
382
+
360
383
  # Plan mode: use SDK's built-in plan permission mode.
361
384
  # In plan mode, Claude outputs a plan then calls ExitPlanMode.
362
385
  # We intercept that to show the plan and ask for approval.
@@ -20,8 +20,11 @@ warnings.filterwarnings("ignore", message="Unable to import Axes3D")
20
20
  warnings.filterwarnings("ignore", category=UserWarning, module="matplotlib")
21
21
 
22
22
  # Force non-interactive matplotlib backend before any import
23
- import matplotlib
24
- matplotlib.use("Agg")
23
+ try:
24
+ import matplotlib
25
+ matplotlib.use("Agg")
26
+ except ImportError:
27
+ pass # matplotlib is a required dep; deferred error in _setup_namespace()
25
28
 
26
29
 
27
30
  # Modules blocked from import inside the sandbox
@@ -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")