Skip to content

Latest commit

 

History

History
200 lines (162 loc) · 10.1 KB

File metadata and controls

200 lines (162 loc) · 10.1 KB

PanelAgent core v0.2.0

panelagent is an LLM-free computation core backed by SQLite. SQLite is the only runtime source of truth. Package seeds contain physical dye data and naming aliases; instrument configuration and antibody inventories can be imported. One database represents one laboratory and can hold any number of freely named antibody libraries, such as Mouse, Human, Isotype, or Controls. Panel generation and diagnosis always operate within exactly one selected library.

Public Python API

The package exports connect, ensure_schema, schema_version, Repo, resolve_fluorochrome, find_valid_panels, generate_candidates, and diagnose_conflicts. Repository instances receive an explicit SQLite connection and keep no global state.

Repo also exposes list_libraries, list_instruments, and paginated list_markers. Repo.antibodies accepts optional limit/offset keyword arguments; existing callers remain unpaginated by default. Dye/channel queries, fluorochrome resolution, generation, and diagnosis accept optional instrument_id filtering. CLI and MCP resolve one instrument before calling instrument-dependent APIs; direct Python calls without a filter retain their existing behavior. find_valid_panels and generate_candidates accept an optional max_search_nodes budget; exceeding it raises ValueError, rather than returning an incomplete result as a completed search.

Database

The schema contains instruments, channels, channel_mapping, fluorochrome_spectra, fluorochrome_aliases, fluorochrome_brightness, and antibodies. Quality state lives directly on an antibody row in quality_flag, quality_notes, and quality_updated_at. Writes are transactional, foreign keys are enabled, and databases use WAL. The antibodies.library column identifies the owning library and participates in the inventory uniqueness constraint.

Database path precedence is:

  1. CLI --db PATH (accepted anywhere in the command line)
  2. PANELAGENT_DB
  3. ~/.local/share/panelagent/panelagent.db

Write-capable CLI commands create parent directories automatically. MCP opens an existing initialized database read-only and never creates directories or schema.

CLI

Install and initialize (from a checkout, or the release wheel — see distribution.md):

pip install -e ".[mcp]"                                   # repo 开发安装
pip install "panelagent-0.2.0-py3-none-any.whl[mcp]"      # 发行 wheel(backend extra 另有)
pa init
pa init --config-dir config --csv Mouse=tests/fixtures/panel_inventory.csv
pa init --config-dir config --inventory-dir inventory

Discovery and inspection:

pa library list --json
pa instrument list --json
pa marker list --library Mouse --limit 100 --offset 0 --json
pa db path
pa db stats --json
pa dye list --laser Violet --instrument-id 1
pa dye show AF488 --json
pa dye alias-add AF-488 "Alexa Fluor® 488"
pa channel list --laser Blue --instrument-id 1
pa antibody list --library Mouse --flag bad --limit 100 --offset 0
pa antibody search BioLegend --json
pa antibody annotate 1 --library Mouse --flag warn --note "Low signal"

marker list 支持 --limit(1–500,默认 100)与 --offset(非负)分页。 antibody list/search 默认不分页;指定 --limit 后可配合 --offset 翻页。 dye/channel 查询支持 --instrument-id 过滤。

Pure panel computation:

pa panel generate --library Mouse --markers CD3,CD4,CD8 --max 10 --json
pa panel diagnose --library Mouse --markers pd1,ctla4,lag3 --json

Every subcommand accepts --json, including when it appears after nested subcommands. Failures exit non-zero and print a machine-readable envelope {"code": "...", "error": "..."}. Codes cover database access (database_missing, database_error, database_unsupported), contract validation (invalid_parameter, invalid_markers, duplicate_markers, unknown_library, no_instruments, multiple_instruments, unknown_instrument, antibody_not_found, target_exists) and entry-point availability (backend_dependency_missing, web_unavailable, backend_unavailable, skill_resources_missing). Zero stored instruments is rejected uniformly by CLI and MCP (no_instruments). Panel generation excludes quality_flag=bad by default; use --include-bad to override it. Warnings and dyes with brightness level 1 or 2 are summarized in each candidate.

Service and distribution entry points (v0.2.0):

pa serve --host 127.0.0.1 --port 8000     # uvicorn 起 backend.app.main:app,注入 PANELAGENT_DB(需 backend extra)
pa web --web-dir /path/to/panelagent-web   # 转调 panelagent.web,启动独立构建的 Next standalone 产物(需 [backend,mcp];库缺失时自动初始化)
pa skill install --dest ~/.agents/skills [--force]   # 分发用户 skill 到 <dest>/panelagent-cli/

The web bundle is built separately per platform (cd frontend && npm run build:bundle, producing dist/panelagent-web/); pa web never builds it.

Panel generation keeps the fewest-options-first marker order. At each backtracking depth it sorts that marker's antibody options by the projected laser utilization (current_load + 1) / capacity, with stable ID order for ties. Loads are recalculated from the current assignments, including after backtracking. This is a soft preference: no extra rejection rule is added, and channel conflicts, quality filtering, brightness summaries, diagnosis, and the maximum solution limit retain their existing behavior. It improves early candidates without guaranteeing a globally optimal distribution.

Capacity comes from COUNT(DISTINCT channel) grouped by channels.laser, excluding blocked channels and rows without laser metadata. With the bundled CytoFLEX seed, usable capacities are B=2, R=3, V=4, Y=4: Violet has five stored channels, but V4_V660 is blocked. Channel-to-laser assignments prefer database metadata and fall back to B/R/V/Y/UV channel prefixes. Options with unknown capacity remain eligible and receive no load penalty.

Each JSON candidate includes laser_distribution (used channel counts, for example {"B": 2, "R": 2, "V": 2, "Y": 2}) and laser_capacity ({"B": 2, "R": 3, "V": 4, "Y": 4}). Text output shows 激光分布: B 2/2 · R 2/3 · V 2/4 · Y 2/4; unknown capacity is displayed as ?. The MCP tools inherit these fields from the same core result.

Inventory-directory library inference recognizes filenames containing 小鼠, 人, or case-insensitive isotype. Unidentified filenames are skipped with a warning. Use --csv Library=PATH for an explicit, freely named library.

CSV imports accept Excel-style UTF-8 BOM and CRLF files, silently discard fully empty trailing rows, and ignore unnamed trailing columns. Rows are skipped with a warning only when both target and fluorochrome are absent. A missing Target falls back to Name; either target or fluorochrome may otherwise remain NULL. Additional named columns such as Quantity are preserved in extra. Hidden files and macOS ._* AppleDouble files are ignored. Re-imports use a NULL-safe identity based on library, catalog number, clone, target, and fluorochrome, so they update existing rows instead of accumulating duplicates.

Literal - placeholders in target, fluorochrome, and clone cells are imported as NULL. Brightness seed names are normalized to spectrum canonical names at seed time: exact spectrum names take precedence, followed by explicit aliases. Unresolved brightness keys produce seed warnings. Full vendor spellings such as PE/Cyanine7, PerCP/Cyanine5.5, and Brilliant Violet 421™ resolve through the same aliases as their short forms. Known dyes without source data remain unresolved rather than receiving guessed brightness values.

MCP

Run pa mcp --db /absolute/path/lab.db to start the optional stdio server using the official Python SDK (mcp>=1.29.1,<2). Install the mcp extra and initialize the selected database with pa init first. MCP does not initialize or modify laboratory data. Each tool opens a short-lived read-only connection and closes it after either success or failure. Stdout belongs exclusively to the MCP protocol; diagnostics go to stderr. No LLM service or API key is needed to run the server.

The server exposes ten tools:

  • list_libraries, list_instruments, list_markers
  • list_fluorochromes, get_fluorochrome, list_channels
  • search_antibodies
  • generate_panel, diagnose_panel
  • db_stats

All tools use core repository and computation functions. Instrument-dependent tools accept instrument_id: one stored instrument is selected automatically; multiple instruments require an explicit selection. Library names come from list_libraries and must be selected explicitly for panel computation.

Search and marker discovery use limit (1–500, default 100) and offset (nonnegative, default 0). Panel tools require 1–64 nonempty markers, trim their names, and reject duplicates after normalization. Generation accepts max_solutions from 1 to 100 (default 10) and has a 100,000-node search budget. Budget exhaustion is a tool error, never evidence of infeasibility.

Tool failures set MCP isError; a completed search with no valid panel instead returns a normal tool result with business status: "error", an empty candidate list, and diagnosis. Channel-conflict-free candidates are deterministic assignments, not an experimental optimization guarantee or an LLM evaluation.

See MCP setup and tool reference for installation, client configuration, response handling, and a complete discovery → generation → diagnosis workflow.

Seed synchronization

The editable authority remains config/. Files under panelagent/data/seed/ are package snapshots and must be recopied or regenerated after edits to config/spectral_data.json, config/fluorochrome_brightness.json, or config/channel_mapping.json. Underscore-prefixed metadata keys are omitted from spectra.json.

The 57 CytoFLEX dye mappings collapse to 14 unique physical channel rows under the required (instrument_id, channel) primary key. AmCyan, V450, V500, and Fixable Viability Stain 780 intentionally resolve without spectra.