Spaces:
Runtime error
A newer version of the Gradio SDK is available: 6.15.2
BPS Eligible School Tool
Overview
This tool lets an LLM or backend service find eligible Boston Public Schools for a student based on:
- grade level
- home address
- ZIP code
- city/state
- home language
It uses the Boston Explore / Avela eligibility API to get the list of ineligible schools, then joins that result with our local school catalog and returns the remaining eligible BPS schools.
In other words:
eligible schools = candidate BPS schools for the grade - ineligible schools returned by Avela
Why this tool exists
The original check_eligibility.py script successfully called the Avela API, but it returned only the API's ineligibleSchools list.
That was not enough for the chatbot pipeline, because the chatbot needs a list of schools the student can actually apply to.
The new tool solves that by:
- calling the eligibility API
- loading the local school data
- filtering to Boston Public Schools only
- filtering to schools that serve the requested grade
- subtracting ineligible schools
- returning the final eligible school list
Main file
The current tool implementation lives in:
check_eligibility_tool.py
Main function
find_eligible_schools(
grade_level: str,
street_address: str,
zip_code: str,
city: str = "Boston",
state: str = "MA",
street_address_line2: str = "",
home_language: str = "English",
dataset_path: str = "raw_data/choice_tool_raw.json",
include_ineligible: bool = False,
) -> dict[str, Any]
What it returns
A dictionary with fields like:
{
"enrollment_period_name": "2026-2027 School Year",
"eligible_schools": [...],
"eligible_count": 16,
"candidate_school_count": 73,
"ineligible_count": 913,
"matched_ineligible_count": 57,
"error": null
}
Important return fields
eligible_schools: the final list the chatbot should useeligible_count: number of eligible schools returnedcandidate_school_count: number of BPS schools in the local dataset that serve the requested gradeineligible_count: total number of ineligible providers returned by Avelamatched_ineligible_count: number of those ineligible providers that matched candidate BPS schools in our local dataseterror: error message if something failed
Tool definition for LLM function calling
The file exposes:
TOOL_DEFINITION
This is the function schema the LLM can use to call the tool.
Tool name:
find_eligible_schools
Expected user-facing parameters:
grade_levelstreet_addresszip_codecitystatestreet_address_line2home_language
Note: dataset_path should stay internal and should not be exposed to the model in production.
Minimal dispatcher
The file also exposes:
handle_tool_call(function_name: str, args: dict[str, Any])
This makes it easy to plug into a future chatbot tool handler.
Example:
args = {
"grade_level": "K2",
"street_address": "2300 Washington St",
"zip_code": "02119",
"city": "Boston",
"state": "MA",
"home_language": "English",
}
result = handle_tool_call("find_eligible_schools", args)
Data sources used
1. Avela API
Used to determine which schools are ineligible for the student.
Endpoints used:
GET /enrollmentPeriodsPOST /formTemplates/{FORM_TEMPLATE_ID}/findEligibility
2. Local dataset
Used to map API references back to school metadata and produce the final eligible list.
Current catalog path:
raw_data/choice_tool_raw.json
This dataset includes more than just BPS schools, so the tool filters to:
provider_type == "Boston Public School"
Eligibility logic
The tool works in this order:
- validate grade and language inputs
- fetch enrollment periods
- build the eligibility API payload
- call Avela's
findEligibility - collect
referenceIdvalues fromineligibleSchools - load the local catalog
- filter the catalog to BPS schools that serve the requested grade
- subtract matching ineligible school IDs
- return the remaining schools as eligible
Set logic
candidate_ids = all BPS school IDs for the requested grade
matched_ineligible_ids = candidate_ids ∩ Avela_ineligible_ids
eligible_ids = candidate_ids - matched_ineligible_ids
Testing
Direct script test
Run:
python3 check_eligibility_tool.py
This runs an example address through the tool and prints the result.
Manual tool-call test
Use test_tool_call.py:
import json
import check_eligibility_tool
from check_eligibility_tool import TOOL_DEFINITION, handle_tool_call, get_enrollment_periods
print("Imported from:", check_eligibility_tool.__file__)
print("Tool name:", TOOL_DEFINITION["name"])
periods, periods_error = get_enrollment_periods()
print("Enrollment periods error:", periods_error)
print("Enrollment periods count:", len(periods))
args = {
"grade_level": "K2",
"street_address": "2300 Washington St",
"zip_code": "02119",
"city": "Boston",
"state": "MA",
"home_language": "English",
"dataset_path": "raw_data/choice_tool_raw.json",
}
result = handle_tool_call("find_eligible_schools", args)
print(json.dumps(result, indent=2))
Run:
python3 test_tool_call.py
Validation that the tool is correct
The tool was validated in a few ways:
1. Count math
For the tested input:
candidate_school_count = 73matched_ineligible_count = 57eligible_count = 16
Check:
73 - 57 = 16
2. Website comparison
The eligible school results matched the Boston Explore website for the tested address.
3. Join logic sanity
The tool only subtracts schools whose local id matches an Avela referenceId after normalization.
Example tested input
result = find_eligible_schools(
grade_level="K2",
street_address="2300 Washington St",
zip_code="02119",
city="Boston",
state="MA",
home_language="English",
dataset_path="raw_data/choice_tool_raw.json",
include_ineligible=False,
)
Observed result summary:
- enrollment period fetched successfully
- 73 candidate BPS schools for K2
- 57 matched as ineligible
- 16 eligible schools returned
Known implementation details
Enrollment periods response format
The Avela enrollmentPeriods endpoint may return a dictionary instead of a raw list.
The tool handles both of these cases:
- list response
- dict response containing
enrollment_period
UUID mappings
The grade and language option UUIDs must match the values from the original working check_eligibility.py implementation.
These mappings were preserved because the original script successfully returned working eligibility results.
Recommended production usage
In production, the chatbot pipeline should work like this:
User question
-> LLM extracts structured args
-> find_eligible_schools tool call
-> return eligible_schools
-> ranking/filtering/retrieval over eligible_schools
-> final chatbot answer
The chatbot should use:
result["eligible_schools"]
as the input to ranking and school recommendation logic.
Suggested follow-up improvements
- Hide
dataset_pathfrom the LLM-facing tool interface. - Add optional debug mode for returning matched ineligible IDs.
- Add unit tests for:
- grade filtering
- ID normalization
- candidate minus ineligible set subtraction
- Add ranking layer on top of
eligible_schools. - Wrap the tool in the actual chatbot tool handler.
Summary
This new tool converts the old “return ineligible schools” flow into a chatbot-ready “return eligible Boston Public Schools” flow.
It is now verified to:
- call the API correctly
- join against local school data correctly
- return eligible BPS schools correctly
- support LLM tool-calling via
TOOL_DEFINITION - support backend execution via
handle_tool_call