OpenAlexScholar Integration Process for Literature Citations in MathModelAgent
The OpenAlexScholar integration process in MathModelAgent involves email validation, API client initialization, paper search with abstract reconstruction, Redis caching, and citation injection into the Writer agent's generated academic papers.
MathModelAgent leverages OpenAlexScholar as a backend service to fetch scholarly metadata and supply literature citations for automated academic writing. The integration pipeline transforms user-provided credentials into a functional citation retrieval system that reconstructs abstracts, caches results, and formats references for LaTeX output. This article examines the complete implementation from the Vue.js frontend through the FastAPI backend to the Writer agent that consumes the citation data.
Prerequisites: Configuring the OpenAlex Email
The integration begins with collecting a valid email address to access OpenAlex's "polite pool." In frontend/src/stores/apiKeys.ts, the application maintains a reactive reference openalexEmail that persists the user's credentials.
When the user submits their email through the API Key dialog, the frontend invokes the validation endpoint. The frontend/src/apis/apiKeyApi.ts module calls POST /validate-openalex-email, which the backend handles in backend/app/routers/modeling_router.py. The router verifies the address by making a test request to https://api.openalex.org/works?mailto={email} and stores the validated email in settings.OPENALEX_EMAIL for global access.
// frontend/src/stores/apiKeys.ts
export const openalexEmail = ref<string>('')
// Validation flow
await validateOpenalexEmail({ email: form.openalex_email })
# backend/app/routers/modeling_router.py
@router.post("/validate-openalex-email", response_model=ValidateOpenalexEmailResponse)
async def validate_openalex_email(request: ValidateOpenalexEmailRequest):
url = f"https://api.openalex.org/works?mailto={request.email}"
async with httpx.AsyncClient() as client:
resp = await client.get(url, timeout=5)
resp.raise_for_status()
return ValidateOpenalexEmailResponse(valid=True, message="Email is valid")
Initializing the OpenAlex Client
The core client implementation resides in backend/app/tools/openalex_scholar.py. The OpenAlexScholar class initializes with a task_id for cache isolation and the validated email for API authentication. The constructor sets the base_url to https://api.openalex.org and prepares a custom User-Agent header containing the mailto parameter.
# backend/app/tools/openalex_scholar.py
class OpenAlexScholar:
def __init__(self, task_id: str, email: str = None):
self.base_url = "https://api.openalex.org"
self.email = email
self.task_id = task_id
self.headers = {"User-Agent": f"OpenAlexScholar/1.0 (mailto:{email})"} if email else {}
Searching and Reconstructing Paper Metadata
The search_papers(query, limit) method executes the primary literature retrieval logic. It constructs a request to the /works endpoint with a select parameter specifying fields including abstract_inverted_index, authorships, cited_by_count, and publication_year.
OpenAlex returns abstracts as inverted index objects rather than plain text. The client calls _get_abstract_from_index() to reconstruct readable abstracts from this token-position mapping. Each work is then wrapped into a ScholarMessage schema defined in backend/app/schemas/response.py.
# backend/app/tools/openalex_scholar.py
async def search_papers(self, query: str, limit: int = 8) -> List[Dict[str, Any]]:
params = {
"search": query,
"per_page": limit,
"select": (
"id,title,display_name,authorships,cited_by_count,doi,"
"publication_year,biblio,abstract_inverted_index"
),
"mailto": self.email
}
response = requests.get(
f"{self.base_url}/works",
params=params,
headers=self.headers
)
response.raise_for_status()
data = response.json()
# Reconstruct abstracts from inverted index
for work in data.get("results", []):
work["abstract"] = self._get_abstract_from_index(
work.get("abstract_inverted_index")
)
return data["results"]
Caching Strategy with Redis
To avoid redundant API calls during iterative paper generation, the integration employs Redis caching via backend/app/services/redis_manager.py. The search_papers method caches results using a key pattern f"openalex:{self.task_id}", ensuring that subsequent invocations for the same modeling task retrieve literature from the cache rather than the OpenAlex API.
This caching layer significantly improves performance when the Writer agent refines citations or regenerates sections of the academic paper.
Injecting Citations into Academic Papers
The backend/app/core/agents/writer_agent.py consumes the OpenAlexScholar service to enrich generated content. When the Writer agent processes a modeling task, it instantiates OpenAlexScholar with the current task.id and global email settings. The agent calls search_papers() with the problem description as the query, then formats the returned metadata into citation strings suitable for academic papers.
# backend/app/core/agents/writer_agent.py
class WriterAgent:
async def generate_paper(self, task: Task):
openalex = OpenAlexScholar(task.id, settings.OPENALEX_EMAIL)
citations = await openalex.search_papers(
task.problem_description,
limit=10
)
# Format for LaTeX/Markdown
formatted_refs = [
f"{c['authorships'][0]['author']['display_name']} "
f"({c['publication_year']}). {c['title']}."
for c in citations
]
# Inject into LLM prompt
paper = await self.llm.generate(
prompt=self._build_prompt(task, formatted_refs)
)
return paper
Summary
- Email Validation: The integration requires a validated OpenAlex email stored in
frontend/src/stores/apiKeys.tsand verified viabackend/app/routers/modeling_router.pybefore any API calls execute. - Client Architecture:
OpenAlexScholarinbackend/app/tools/openalex_scholar.pymanages the HTTP session, User-Agent headers, and abstract reconstruction from inverted index data. - Metadata Extraction: The
search_papers()method querieshttps://api.openalex.org/workswith explicit field selection and reconstructs readable abstracts using_get_abstract_from_index(). - Performance Optimization: Redis caching through
backend/app/services/redis_manager.pystores results pertask_idto minimize external API requests. - Agent Integration: The Writer agent in
backend/app/core/agents/writer_agent.pyinstantiates the scholar client, retrieves relevant papers based on the problem description, and injects formatted citations into the final academic output.
Frequently Asked Questions
Why does OpenAlexScholar require an email address?
OpenAlex provides a "polite pool" of resources for users who identify themselves via the mailto parameter. The integration stores this email in settings.OPENALEX_EMAIL and includes it in every request header to ensure reliable API access and comply with OpenAlex's usage policies.
How does the system handle abstract reconstruction?
The OpenAlex API returns abstracts as abstract_inverted_index objects, which map tokens to their positions in the text. The _get_abstract_from_index() method in backend/app/tools/openalex_scholar.py reverses this mapping to reconstruct the original abstract text before wrapping it in the ScholarMessage schema.
What happens if the same query runs multiple times during paper generation?
The search_papers() method caches results in Redis using the key pattern openalex:{task_id}. Subsequent calls with the same task identifier retrieve data from the cache rather than making redundant requests to the OpenAlex API, improving response times and reducing rate limit consumption.
Which agent is responsible for formatting the citations?
The Writer agent located in backend/app/core/agents/writer_agent.py instantiates OpenAlexScholar, retrieves relevant papers based on the problem description, and formats the authorships, publication_year, and title fields into citation strings suitable for LaTeX or Markdown academic papers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →