Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
3abfcdd
Added code for JSON oriented model approach
deepnayak Jun 17, 2024
43c77e6
chore: Update code formatting and editor settings
deepnayak Jun 18, 2024
b0ddec5
refactor: Reorganize imports and update code formatting
deepnayak Jun 18, 2024
2727fc8
chore: Refactor build_index function to simplify code
deepnayak Jun 18, 2024
c770b71
Minor changes
deepnayak Jun 18, 2024
cd314da
Minor changes
deepnayak Jun 18, 2024
80e24dc
Removed conflicting flake8 error
deepnayak Jun 18, 2024
a7f98f7
Updated model in INSTALL.md
deepnayak Jun 19, 2024
9a06fa5
Resolved PR Comments
deepnayak Jun 23, 2024
a4d1502
Added query pipeline feature and agent based approach
deepnayak Jun 25, 2024
d67c1f7
Merge branch 'main' of https://github.com/genomehubs/goat-nlp into ag…
deepnayak Jun 25, 2024
42b0542
Minor improvements
deepnayak Jun 25, 2024
8cdd7e4
refactor: Refactor validators.py for improved JSON validation and cor…
deepnayak Jul 2, 2024
1d29fc1
Approach using only query pipeline
deepnayak Jul 3, 2024
d9faf5c
Improved query pipeline
deepnayak Jul 4, 2024
88e5736
Improved query pipeline
deepnayak Jul 4, 2024
91186af
Fixed sourcery issues
deepnayak Jul 5, 2024
32aed93
Minor changes
deepnayak Jul 5, 2024
32dae8d
Improved rank and entity selection
deepnayak Jul 16, 2024
fe131e8
Minor changes
deepnayak Jul 16, 2024
c55ec68
Quick Fix for record queries
deepnayak Jul 17, 2024
ffef277
add test framework
rjchallis Jul 23, 2024
dd95ae1
add extra test case
rjchallis Jul 23, 2024
199cfb6
Added debug json to html
deepnayak Jul 30, 2024
fa79d73
Styling changes
deepnayak Jul 31, 2024
f93d997
Merge branch 'main' of https://github.com/genomehubs/goat-nlp into de…
deepnayak Aug 9, 2024
dbab17c
Minor changes
deepnayak Aug 9, 2024
a979244
Minor changes
deepnayak Aug 13, 2024
300c7bd
Minor performance improvement
deepnayak Aug 15, 2024
7761c52
Improved query pipeline
deepnayak Aug 21, 2024
c79a073
Pipeline improvements
deepnayak Aug 28, 2024
32ad9ad
Performance improvement
deepnayak Sep 4, 2024
8a6e025
modify prompts to improve entity and attribute value handling
rjchallis Sep 9, 2024
97b842a
add methods for MCP approach
rjchallis Nov 28, 2025
238edc6
improve prompts to make sure LLMs check available attributes and unde…
rjchallis Dec 1, 2025
88e7bcb
improve attrinbut selection and add support for wildcards in names
rjchallis Dec 1, 2025
de53ac9
add get_goat_record tool for lineage and attribute information
rjchallis Dec 1, 2025
bfe6bde
improve and/or distinction
rjchallis Dec 1, 2025
d852aea
add result table output
rjchallis Dec 1, 2025
e49d696
add attribute validation in case llm has skipped attribute context
rjchallis Dec 2, 2025
c124c86
add an example queries tool
rjchallis Dec 2, 2025
fe99e07
catch missing operator in value validation
rjchallis Dec 2, 2025
00f005f
add sources and histogram reports
rjchallis Dec 2, 2025
f7d0053
add UI/API to test mcp across various models
rjchallis Dec 3, 2025
ef6a115
add histogram tests
rjchallis Dec 4, 2025
fe5ca95
refactor helper functions
rjchallis Dec 4, 2025
da3c7f3
refactor code
rjchallis Dec 4, 2025
f386571
improve lower powered llm performance with alternate goat_query tool
rjchallis Dec 5, 2025
7f7464f
enforce sequential workflow
rjchallis Dec 11, 2025
fa1033c
improve name and rank handling
rjchallis Dec 11, 2025
cf3b243
improve attribute context
rjchallis Dec 12, 2025
28f65b4
refactor get_metadata_for_attribute return type and improve modifier …
rjchallis Dec 12, 2025
20389c3
improve name prefix handling
rjchallis Dec 12, 2025
47e85a0
add support for excluding names from tax tree
rjchallis Dec 15, 2025
ab174ad
fix assembly index attribute lookup
rjchallis Dec 15, 2025
c230ece
add user-friendly page for brwsers hitting /mcp endpoint
rjchallis Feb 10, 2026
3e26c19
make function names generic and extend config based site-scoping to d…
rjchallis Feb 11, 2026
3b15f9f
improve function reuse for process_ tools
rjchallis Feb 12, 2026
9a7a295
remove redundant code
rjchallis Feb 12, 2026
fbab121
add report axis processing
rjchallis Feb 13, 2026
65df573
update host
rjchallis Feb 13, 2026
aa7f269
add config file
rjchallis Feb 13, 2026
106f2f0
make error messages reusable
rjchallis Feb 16, 2026
94ae68e
improve validation and error mesaages
rjchallis Feb 17, 2026
9fe127b
add response_format to check_taxon_exists
rjchallis Feb 17, 2026
868f06e
refactor and add machine readable logging
rjchallis Feb 23, 2026
b88dcec
add structured logging
rjchallis Mar 30, 2026
59ad2e9
refactor get_attribute_guide and get_attribute_info to return formatt…
rjchallis Apr 1, 2026
115017b
add agents and contributing files
rjchallis Apr 2, 2026
9563646
remove public-api code
rjchallis Apr 2, 2026
80b5e33
move CONTRIBUTING to top level
rjchallis Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# GitHub Copilot instructions for goat-nlp

## Project structure

```
src/mcp-server/
server.py # FastMCP server entry point
config.py # Imports from config_site.py (not tracked) or config_example.py
config_example.py # Edit this to create config_site.py for local config
prompts/
system.py # Multi-stage system prompt (get_multi_stage_prompt)
query_parser.py # Legacy and default single-stage prompts
tools/
__init__.py # Registers all tool modules via register_tools(mcp)
attributes.py # get_attribute_info, get_attribute_selection_context → return str
attribute_guide.py # get_attribute_guide → returns str
utilities.py # choose_search_index, check_taxon_exists, get_valid_ranks
process_identifiers.py # process_identifiers → returns artifact dict
process_attributes.py # process_attributes → returns artifact dict
process_axis.py # process_axis → returns artifact dict
query_parser.py # submit_query → returns result dict
report.py # get_report → returns result dict
helpers/
api.py # make_api_request — ONLY place for HTTP calls
fetch.py # fetch_valid_types — attribute metadata cache
query.py # URL/query string construction
urls.py # URL update utilities
constants.py # FIELD_CACHE (module-level attribute cache)
validation.py # validate_attributes, validate_attribute_name
errors.py # ToolExecutionError and error message helpers
formatting.py # process_result_table, format_result_table
search_index.py # infer_index_from_query
processor_common.py # finalise_and_store (artifact store writes)
tests/
smoke_histogram.py
smoke_submit_query_and_advanced_search.py
test_histogram_assert.py
test_local_model_integration_scaffold.py
```

## Return type convention

- **Helper tools** (`get_attribute_info`, `get_attribute_selection_context`,
`get_attribute_guide`) return `str` (markdown). FastMCP serialises these as
`TextContent` — the LLM reads them directly.
- **Pipeline tools** (`process_*`, `submit_query`, `get_report`) return `dict`
with a structured envelope. FastMCP serialises these as `structured_content`
alongside `TextContent`.

## Hard constraints

**No new API calls outside the helpers layer.**
All HTTP is done through `make_api_request()` in `tools/helpers/api.py`.
A planned SDK migration will replace all direct API interactions. Until it
lands, do not add new `make_api_request` calls, new endpoints, or new
response-parsing logic anywhere outside `helpers/api.py`, `helpers/fetch.py`,
and `tools/utilities.py`.

**No new URL construction.**
All query URL building goes through `tools/helpers/query.py`. Do not construct
API or web URLs inline in tool functions.

**Config constants only — no hardcoded site values.**
Use `DATASTORE_NAME`, `API_BASE`, `WEB_URL`, etc. from `config.py`. Never
write `"GoaT"`, `"goat.genomehubs.org"`, or similar strings in tool code.

**Tool registration via `register_tools`.**
Each tool module exposes `register_tools(mcp)`. Import and call it from
`tools/__init__.py`. Do not decorate tool functions with `@mcp.tool()` inline.

**Every public tool must call `log_tool_usage()`.**
Both success and failure paths. Required fields: `tool_name`, `params`,
`duration_ms`, `success`. Failure paths also pass `error=` and optionally
`exc=`.

## Prompt editing rules

LLM instructions live as `TOOL_NAME_PROMPT` string constants in the same file
as the tool, assigned to the function's `__doc__`. When editing them:

1. **Fix the instruction, not the example.** If a query fails, find the missing
or ambiguous rule and fix it. Do not add the failing query as a new example.

2. **One example per concept.** A single case is enough to demonstrate a
pattern. Remove examples that duplicate a rule shown elsewhere in the prompt.

3. **Domain terms are fine; specific instances are not.** Attribute names
(`genome_size`, `assembly_level`) and rank names (`phylum`, `species`) are
unavoidable. Specific taxon names, accession numbers, and project codes
should be replaced with placeholders unless they are the clearest way to
show a structural point.

4. **Positive over prohibitive.** Write "pass values as a list" rather than
"do not pass as a string". Prohibitions accumulate; positive rules compose.

5. **Rewrite bullets, don't append to them.** If a bullet is unclear, rewrite
it. Do not add a sub-bullet or parenthetical caveat.

6. **Prompts must not grow without reason.** Check line count before and after.
A fix should not increase length unless it adds support for a new concept.

## Testing

No automated runner. After any change:

1. Run the smoke tests:
```
python src/mcp-server/tests/smoke_histogram.py
python src/mcp-server/tests/smoke_submit_query_and_advanced_search.py
python src/mcp-server/tests/test_histogram_assert.py
```
2. Verify README examples manually against a running server. These are the
regression baseline.

## Known bugs (do not duplicate the root causes)

- `get_report` registered twice in `tools/report.py` `register_tools()`.
- `get_valid_ranks` registered twice in `tools/utilities.py` `register_tools()`.
- `attribute_guide.register_tools` not called from `tools/__init__.py` —
`get_attribute_guide` is currently unreachable as an MCP tool.
7 changes: 7 additions & 0 deletions .vscode/mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"servers": {
"goat": {
"url": "http://127.0.0.1:8008/mcp"
}
}
}
40 changes: 30 additions & 10 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
{
"git.ignoreLimitWarning": true,
"editor.formatOnSave": true,
"flake8.args": [
"--max-line-length=118"
],

// Enable formatting and linting for Python
"[python]": {
"editor.codeActionsOnSave": {
"source.organizeImports.python": "explicit"
},
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
}
}
"editor.formatOnType": true,
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},

// Python specific
"python.formatting.provider": "black",
"python.formatting.blackArgs": ["--line-length", "88"],
"python.linting.flake8Enabled": true,
"python.linting.enabled": true,
"python.linting.flake8Args": ["--max-line-length=88"],
"python.sortImports.args": ["--profile", "black"],

// Enable error lens
"errorLens.enabled": true,

// iSort will respect Black style
"isort.args": ["--profile", "black"],

// Enable auto save
"files.autoSave": "onFocusChange",
"cSpell.words": ["Kinfin", "proteome"],
"python-envs.defaultEnvManager": "ms-python.python:conda",
"python-envs.defaultPackageManager": "ms-python.python:conda",
"python-envs.pythonProjects": []
}
194 changes: 194 additions & 0 deletions AB_TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# A/B Testing: Parsing vs Simple Search Approach

## Overview

Two different approaches for LLM interaction with GoaT:

1. **Simple Search (Default)** - LLM chooses simple_search or search_goat tools directly
2. **Parse Query (Experimental)** - LLM extracts structured intent, backend processes

## Switching Between Approaches

### MCP Server

Set the `GOAT_PROMPT_STYLE` environment variable:

```bash
# Use default simple_search approach
export GOAT_PROMPT_STYLE=simple
python -m mcp-server

# Use experimental parse_user_query approach
export GOAT_PROMPT_STYLE=parser
python -m mcp-server
```

### Public API

The public API exposes both approaches. LLMs can use either:

- `goat_parse_user_query` (experimental parsing approach)
- `goat_simple_search` (simple approach)
- `goat_search_goat` (advanced approach)

## Key Differences

### Simple Search Approach (Current Default)

**LLM Responsibilities:**

- Choose between simple_search and search_goat
- Map "families" → what_to_count parameter
- Translate common names to scientific names
- Identify specific_attribute names
- Handle missing vs present logic

**Backend Responsibilities:**

- Construct GoaT API URL
- Execute query
- Format results

**Pros:**

- Clear, straightforward tool interface
- Works well for most queries
- Easy to understand

**Cons:**

- LLMs struggle with edge cases:
- Missing rank extraction
- long_list vs sequencing_status confusion
- Handling "missing" data (exclusions)
- Direct vs ancestral vs estimated modifiers

### Parse Query Approach (Experimental)

**LLM Responsibilities:**

- Extract intent (count/table/histogram/record)
- Extract taxon (if mentioned)
- Extract rank (if mentioned - backend handles if missed)
- Extract attributes with modifiers

**Backend Responsibilities:**

- Infer search_index from user_query (taxon/assembly/sample)
- Handle missing rank extraction from user_query
- Disambiguate long_list vs sequencing_status
- Convert "missing" modifier to exclusions
- Handle "direct" modifier (exclude ancestral/estimated)
- Process aggregate modifiers (min/max/median)
- Construct GoaT API URL
- Execute query
- Format results

**Pros:**

- Separates understanding from implementation
- Backend handles complex edge cases
- More robust to LLM capability differences
- Extensible to new modifiers

**Cons:**

- More complex backend processing required
- Currently incomplete implementation
- Experimental status

## Modifier System

The parse_user_query approach introduces attribute modifiers:

### Data Availability Modifiers

- `"missing"` - Species WITHOUT this attribute

- Example: `{"name": "genome_size", "modifier": "missing"}`
- Backend converts to exclusions: `exclude=["Direct", "Ancestral", "Estimated"]`

- `"direct"` - Only directly measured values

- Example: `{"name": "genome_size", "modifier": "direct"}`
- Backend excludes: `exclude=["Ancestral", "Estimated"]`

- `"ancestral"` - Include ancestral values

- Backend includes both direct and ancestral

- `"estimated"` - Include estimated values

### Aggregate Function Modifiers

- `"min"`, `"max"`, `"median"`, `"length"` - Aggregate functions
- Example: `{"name": "genome_size", "modifier": "max"}`
- Backend maps to GoaT API aggregate parameters

## Implementation Status

### ✅ Completed

- parse_user_query tool created
- MCP server prompt switching (GOAT_PROMPT_STYLE env var)
- Public API tool definition (goat_parse_user_query)
- Parser-based system prompt
- Modifier parameter structure
- Automatic search_index inference using choose_search_index

### 🚧 In Progress

- Backend processing of modifiers
- Automatic rank extraction from user_query
- long_list vs sequencing_status disambiguation
- Exclusion handling for "missing" modifier

### 📋 To Do

- Complete backend processing implementation
- Add tests comparing both approaches
- Measure accuracy differences
- Performance comparison
- Documentation of modifier extensions

## Testing

To test both approaches:

```bash
# Terminal 1: Run with simple approach
export GOAT_PROMPT_STYLE=simple
python -m mcp-server

# Terminal 2: Run with parser approach
export GOAT_PROMPT_STYLE=parser
python -m mcp-server

# Compare results for the same queries
```

## Extending Modifiers

The modifier system can be extended to support additional GoaT API features:

- `"summary"` - For GoaT summary parameters
- `"binned"` - For histogram binning
- Custom aggregate functions
- Field-specific modifiers

Add new modifiers to the enum in:

- `tools/query_parser.py` (docstring)
- `public-api/app/services/goat_tools.py` (input_schema)
- Backend processing logic

## Recommendation

Start with the **simple search approach** (default) since it's fully implemented and tested.

Use **parse query approach** for:

- Testing LLMs with varying capabilities
- Queries with complex "missing" semantics
- Queries requiring aggregate functions
- Research into separation of concerns
Loading
Loading