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.
- celltype_cli-0.2.1/.git +1 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.gitignore +1 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/PKG-INFO +20 -4
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/README.md +7 -2
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/install.sh +19 -11
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/pyproject.toml +15 -2
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/__init__.py +1 -1
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/config.py +9 -2
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/doctor.py +53 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/mcp_server.py +105 -20
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/runner.py +6 -1
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/session.py +1 -1
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/system_prompt.py +17 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/cli.py +712 -15
- celltype_cli-0.2.1/src/ct/cloud/__init__.py +3 -0
- celltype_cli-0.2.1/src/ct/cloud/auth.py +197 -0
- celltype_cli-0.2.1/src/ct/cloud/client.py +227 -0
- celltype_cli-0.2.1/src/ct/cloud/local_runner.py +274 -0
- celltype_cli-0.2.1/src/ct/cloud/router.py +332 -0
- celltype_cli-0.2.1/src/ct/cloud/structure_inputs.py +50 -0
- celltype_cli-0.2.1/src/ct/cloud/tool_entrypoint.py +56 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/models/llm.py +1 -1
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/__init__.py +72 -2
- celltype_cli-0.2.1/src/ct/tools/_container_tools.py +97 -0
- celltype_cli-0.2.1/src/ct/tools/_schema_contract.py +44 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2/Dockerfile +47 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2/implementation.py +297 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2/patch_jackhmmer.py +11 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2/tool.yaml +70 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/Dockerfile +43 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/implementation.py +389 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/tool.yaml +83 -0
- celltype_cli-0.2.1/src/ct/tools/alphafold2-multimer/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/boltz2/Dockerfile +20 -0
- celltype_cli-0.2.1/src/ct/tools/boltz2/implementation.py +104 -0
- celltype_cli-0.2.1/src/ct/tools/boltz2/tool.yaml +52 -0
- celltype_cli-0.2.1/src/ct/tools/boltz2/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/diffdock/Dockerfile +26 -0
- celltype_cli-0.2.1/src/ct/tools/diffdock/implementation.py +225 -0
- celltype_cli-0.2.1/src/ct/tools/diffdock/tool.yaml +53 -0
- celltype_cli-0.2.1/src/ct/tools/diffdock/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/esm2/Dockerfile +17 -0
- celltype_cli-0.2.1/src/ct/tools/esm2/implementation.py +55 -0
- celltype_cli-0.2.1/src/ct/tools/esm2/tool.yaml +41 -0
- celltype_cli-0.2.1/src/ct/tools/esm2/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/esmfold/Dockerfile +18 -0
- celltype_cli-0.2.1/src/ct/tools/esmfold/implementation.py +98 -0
- celltype_cli-0.2.1/src/ct/tools/esmfold/tool.yaml +36 -0
- celltype_cli-0.2.1/src/ct/tools/esmfold/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/evo2/Dockerfile +18 -0
- celltype_cli-0.2.1/src/ct/tools/evo2/implementation.py +174 -0
- celltype_cli-0.2.1/src/ct/tools/evo2/tool.yaml +69 -0
- celltype_cli-0.2.1/src/ct/tools/evo2/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/genmol/Dockerfile +13 -0
- celltype_cli-0.2.1/src/ct/tools/genmol/implementation.py +101 -0
- celltype_cli-0.2.1/src/ct/tools/genmol/tool.yaml +71 -0
- celltype_cli-0.2.1/src/ct/tools/genmol/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/molmim/Dockerfile +13 -0
- celltype_cli-0.2.1/src/ct/tools/molmim/implementation.py +97 -0
- celltype_cli-0.2.1/src/ct/tools/molmim/tool.yaml +66 -0
- celltype_cli-0.2.1/src/ct/tools/molmim/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/msa-search/Dockerfile +23 -0
- celltype_cli-0.2.1/src/ct/tools/msa-search/implementation.py +428 -0
- celltype_cli-0.2.1/src/ct/tools/msa-search/tool.yaml +59 -0
- celltype_cli-0.2.1/src/ct/tools/msa-search/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/openfold2/Dockerfile +47 -0
- celltype_cli-0.2.1/src/ct/tools/openfold2/implementation.py +508 -0
- celltype_cli-0.2.1/src/ct/tools/openfold2/tool.yaml +103 -0
- celltype_cli-0.2.1/src/ct/tools/openfold2/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/openfold3/Dockerfile +49 -0
- celltype_cli-0.2.1/src/ct/tools/openfold3/implementation.py +545 -0
- celltype_cli-0.2.1/src/ct/tools/openfold3/tool.yaml +94 -0
- celltype_cli-0.2.1/src/ct/tools/openfold3/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/proteinmpnn/Dockerfile +24 -0
- celltype_cli-0.2.1/src/ct/tools/proteinmpnn/implementation.py +97 -0
- celltype_cli-0.2.1/src/ct/tools/proteinmpnn/tool.yaml +50 -0
- celltype_cli-0.2.1/src/ct/tools/proteinmpnn/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/rfdiffusion/Dockerfile +33 -0
- celltype_cli-0.2.1/src/ct/tools/rfdiffusion/implementation.py +425 -0
- celltype_cli-0.2.1/src/ct/tools/rfdiffusion/tool.yaml +64 -0
- celltype_cli-0.2.1/src/ct/tools/rfdiffusion/tool_entrypoint.py +27 -0
- celltype_cli-0.2.1/src/ct/tools/tool_entrypoint.py +27 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/terminal.py +7 -1
- celltype_cli-0.2.1/src/ct/update_checker.py +111 -0
- celltype_cli-0.2.1/tests/e2e/__init__.py +0 -0
- celltype_cli-0.2.1/tests/e2e/kras_g12c.fasta +6 -0
- celltype_cli-0.2.1/tests/e2e/sotorasib.smi +1 -0
- celltype_cli-0.2.1/tests/e2e/test_e2e_cloud.py +241 -0
- celltype_cli-0.2.1/tests/test_billing.py +133 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_cli.py +16 -0
- celltype_cli-0.2.1/tests/test_cloud_auth.py +151 -0
- celltype_cli-0.2.1/tests/test_cloud_client.py +170 -0
- celltype_cli-0.2.1/tests/test_compute_router.py +332 -0
- celltype_cli-0.2.1/tests/test_e2e_local_gpu.py +260 -0
- celltype_cli-0.2.1/tests/test_extensibility.py +182 -0
- celltype_cli-0.2.1/tests/test_fallback_routing.py +172 -0
- celltype_cli-0.2.1/tests/test_gpu_registry.py +213 -0
- celltype_cli-0.2.1/tests/test_local_runner.py +235 -0
- celltype_cli-0.2.1/tests/test_modal_generation.py +143 -0
- celltype_cli-0.2.1/tests/test_observability.py +118 -0
- celltype_cli-0.2.1/tests/test_security_mitigations.py +220 -0
- celltype_cli-0.2.1/tests/test_setup_gpu.py +114 -0
- celltype_cli-0.2.1/tests/test_stripe_integration.py +324 -0
- celltype_cli-0.1.3/.claude/settings.local.json +0 -96
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/apply.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/archive.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/bulk-archive.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/continue.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/explore.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/ff.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/new.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/onboard.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/sync.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/commands/opsx/verify.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-apply-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-archive-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-bulk-archive-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-continue-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-explore/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-ff-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-new-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-onboard/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-sync-specs/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.claude/skills/openspec-verify-change/SKILL.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.dockerignore +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/.github/workflows/ci.yml +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/CLAUDE.md +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/Dockerfile +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/Dockerfile.api +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/LICENSE +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/assets/bixbench_benchmark.png +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/assets/ct2.gif +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/docker-compose.yml +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/openspec/config.yaml +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/scripts/prepare_datasets.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/scripts/prepare_l1000.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/settings.json +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/case_studies.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/knowledge.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/loop.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/orchestrator.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/sandbox.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/trace_store.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/trajectory.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/types.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/agent/workflows.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/app.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/config.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/api/engine.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/compute_providers.json +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/cro_database.json +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/downloader.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/data/loaders.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/benchmarks.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/governance.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/ingest.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/reasoning.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/schema_monitor.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/kb/substrate.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/models/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/_compound_resolver.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/biomarker.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/cellxgene.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/chemistry.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/claude.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/clinical.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/clue.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/code.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/combination.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/compute.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/cro.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/data_api.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/design.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/dna.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/experiment.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/expression.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/files.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/genomics.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/http_client.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/imaging.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/intel.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/literature.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/network.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/notification.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/omics.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/ops.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/parity.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/pk.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/protein.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/regulatory.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/remote_data.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/report.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/repurposing.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/safety.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/shell.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/singlecell.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/statistics.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/structure.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/target.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/translational.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/tools/viability.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/markdown.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/status.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/suggestions.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/src/ct/ui/traces.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/__init__.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/conftest.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/fixtures/plan_snapshot.txt +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/fixtures/trace_snapshot.txt +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_api_smoke.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_cellxgene.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_chemistry_new.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_claude.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_clue.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_code.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_compute.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_config.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_cro.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_data_api.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_data_api_service.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_design.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_dna.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_doctor.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_downloader.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_engine.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_experiment.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_files.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_future_backends_todo.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_html_report.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_http_client.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_imaging.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_benchmarks.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_governance.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_ingest.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_reasoning.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_schema_monitor.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_kb_substrate.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_knowledge.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_llm.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_mention_completer.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_network.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_notebook.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_notification.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_omics.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_ops.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_parity_tools.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_parkinsons_toolchain_smoke.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_patent_search.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_plan_display.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_protein.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_registry.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_remote_data.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_repurposing.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_sandbox.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_sdk_streaming.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_session.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_shell.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_singlecell.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_status.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_structure.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_target.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_terminal.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_terminal_integration.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_tools.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_trace_store.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_traces.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_trajectory.py +0 -0
- {celltype_cli-0.1.3 → celltype_cli-0.2.1}/tests/test_workflows.py +0 -0
celltype_cli-0.2.1/.git
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitdir: ../.git/modules/cli
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: celltype-cli
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: CellType CLI — An autonomous agent for drug discovery research
|
|
5
5
|
Author: CellType Inc.
|
|
6
|
-
License
|
|
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/
|
|
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
|
|
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/
|
|
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
|
|
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/
|
|
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}
|
|
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 "$
|
|
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
|
-
|
|
87
|
-
info "
|
|
88
|
-
info ""
|
|
89
|
-
|
|
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
|
|
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",
|
|
@@ -29,11 +29,10 @@ logger = logging.getLogger("ct.config")
|
|
|
29
29
|
|
|
30
30
|
DEFAULTS = {
|
|
31
31
|
"llm.provider": "anthropic",
|
|
32
|
-
"llm.model": "claude-
|
|
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
|
-
#
|
|
114
|
-
#
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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")
|