Skip to content

Add Open Library Omi integration app#7415

Open
absalonCRC wants to merge 2 commits into
BasedHardware:mainfrom
absalonCRC:omi-open-library-app
Open

Add Open Library Omi integration app#7415
absalonCRC wants to merge 2 commits into
BasedHardware:mainfrom
absalonCRC:omi-open-library-app

Conversation

@absalonCRC
Copy link
Copy Markdown

Summary

  • add a standalone Open Library x Omi app under plugins/omi-open-library-app
  • expose no-auth chat tools for book search, work/ISBN details, and subject recommendations
  • include Railway/Heroku deployment files and local usage docs

Validation

  • plugins/omi-open-library-app/.venv/bin/python -m py_compile plugins/omi-open-library-app/main.py
  • FastAPI TestClient manifest checks for all 3 tools and type: object schemas
  • helper checks for string/invalid limits, work IDs, ISBN cleanup, and subject slugs
  • live Open Library smoke checks for search_books, get_book_details, and search_subject
  • git diff --cached --check

Candidate integration app for #3120.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 20, 2026

Greptile Summary

This PR adds a new standalone Omi plugin app (plugins/omi-open-library-app) that wraps the public Open Library API and exposes three no-auth chat tools — search_books, get_book_details, and search_subject — via a FastAPI server ready for Railway/Heroku deployment.

  • main.py: Implements a shared httpx.AsyncClient (managed via lifespan), three POST tool endpoints with input sanitisation helpers, and a /.well-known/omi-tools.json manifest; get_book_details correctly handles 404s, but search_subject does not, returning a raw HTTP error string instead of a friendly message when an unknown subject slug returns 404.
  • Manifest schemas: search_books and get_book_details omit required-parameter constraints, so an LLM calling the tool with no parameters will receive a runtime error rather than a schema-level rejection.
  • Deployment files: Procfile, railway.toml, runtime.txt, and requirements.txt are all consistent and correctly pin dependencies.

Confidence Score: 4/5

Safe to merge; the app is a new, self-contained plugin with no changes to existing code paths.

The two findings are quality/consistency gaps in a brand-new standalone plugin. The missing 404 handling in search_subject exposes a raw HTTP error string to users when an unrecognised subject slug is queried, and the absent schema constraints in two tool manifests mean an LLM has no upfront signal that parameters are required. Neither issue affects existing functionality or other parts of the codebase.

plugins/omi-open-library-app/main.py — exception handling consistency in search_subject and manifest schema completeness.

Important Files Changed

Filename Overview
plugins/omi-open-library-app/main.py Core FastAPI app with three Omi chat tool endpoints; exception handling is inconsistent between search_subject (no 404 specialisation) and get_book_details (has it), and tool manifest schemas for search_books/get_book_details omit required-parameter constraints
plugins/omi-open-library-app/requirements.txt Pins fastapi, uvicorn, pydantic, and httpx to specific versions; no issues
plugins/omi-open-library-app/railway.toml Standard Railway deployment config with health check, restart policy, and NIXPACKS builder; no issues
plugins/omi-open-library-app/Procfile Single-line Heroku Procfile using uvicorn with PORT passthrough; correct
plugins/omi-open-library-app/README.md Clear setup, usage, and deployment docs with curl examples for all three tools

Sequence Diagram

sequenceDiagram
    participant Omi as Omi Client
    participant App as FastAPI App
    participant OL as Open Library

    Omi->>App: GET /.well-known/omi-tools.json
    App-->>Omi: Tool manifest with 3 tools

    Omi->>App: POST /tools/search_books
    App->>OL: GET /search.json with query params
    OL-->>App: docs array
    App-->>Omi: ChatToolResponse with formatted results

    Omi->>App: POST /tools/get_book_details
    alt work_id supplied
        App->>OL: GET /works/OLxxxxW.json
    else isbn supplied
        App->>OL: GET /api/books with bibkeys param
    end
    OL-->>App: work or edition metadata
    App-->>Omi: ChatToolResponse with formatted details

    Omi->>App: POST /tools/search_subject
    App->>OL: GET /subjects/slug.json
    OL-->>App: works array
    App-->>Omi: ChatToolResponse with subject book list
Loading

Reviews (1): Last reviewed commit: "Add Open Library Omi integration app" | Re-trigger Greptile

Comment on lines +389 to +399
try:
data = await _request_json(f"/subjects/{slug}.json", params={"limit": limit})
works = data.get("works", [])[:limit]
if not works:
return ChatToolResponse(result=f"No books found for subject {subject}.")

title = _clean_text(data.get("name")) or subject
lines = [_format_subject_work(work, i + 1) for i, work in enumerate(works)]
return ChatToolResponse(result=f"Open Library books for subject {title}:\n\n" + "\n\n".join(lines))
except (httpx.HTTPError, ValueError) as exc:
return ChatToolResponse(error=f"Open Library subject search failed: {exc}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 search_subject doesn't handle 404 responses with a friendly message. Open Library's /subjects/{slug}.json endpoint returns HTTP 404 for unrecognised subject slugs. _request_json calls raise_for_status(), which raises httpx.HTTPStatusError — a subclass of httpx.HTTPError, so it falls into the generic catch block and surfaces as "Open Library subject search failed: Client error '404 Not Found'…" instead of a clean "no books found" reply. get_book_details already handles this correctly with a dedicated except httpx.HTTPStatusError clause.

Suggested change
try:
data = await _request_json(f"/subjects/{slug}.json", params={"limit": limit})
works = data.get("works", [])[:limit]
if not works:
return ChatToolResponse(result=f"No books found for subject {subject}.")
title = _clean_text(data.get("name")) or subject
lines = [_format_subject_work(work, i + 1) for i, work in enumerate(works)]
return ChatToolResponse(result=f"Open Library books for subject {title}:\n\n" + "\n\n".join(lines))
except (httpx.HTTPError, ValueError) as exc:
return ChatToolResponse(error=f"Open Library subject search failed: {exc}")
try:
data = await _request_json(f"/subjects/{slug}.json", params={"limit": limit})
works = data.get("works", [])[:limit]
if not works:
return ChatToolResponse(result=f"No books found for subject {subject}.")
title = _clean_text(data.get("name")) or subject
lines = [_format_subject_work(work, i + 1) for i, work in enumerate(works)]
return ChatToolResponse(result=f"Open Library books for subject {title}:\n\n" + "\n\n".join(lines))
except httpx.HTTPStatusError as exc:
if exc.response.status_code == 404:
return ChatToolResponse(result=f"No books found for subject {subject}.")
return ChatToolResponse(error=f"Open Library subject search failed: {exc}")
except (httpx.HTTPError, ValueError) as exc:
return ChatToolResponse(error=f"Open Library subject search failed: {exc}")

Comment on lines +198 to +218
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free-form book search query, such as a title, author, topic, or ISBN.",
},
"author": {
"type": "string",
"description": "Optional author name filter.",
},
"subject": {
"type": "string",
"description": "Optional subject filter, such as science fiction or product management.",
},
"limit": {
"type": "integer",
"description": "Maximum books to return. Defaults to 5, maximum 10.",
},
},
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The search_books manifest schema has no required field, but the endpoint will reject a call with no query, author, or subject. An LLM relying solely on the schema has no way to know this constraint and will receive a runtime error response instead of schema-level guidance. Adding a description hint or anyOf constraint lets the Omi platform surface the requirement before the call is made. The same gap exists in get_book_details — neither work_id nor isbn is marked required, yet at least one must be present.

Suggested change
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free-form book search query, such as a title, author, topic, or ISBN.",
},
"author": {
"type": "string",
"description": "Optional author name filter.",
},
"subject": {
"type": "string",
"description": "Optional subject filter, such as science fiction or product management.",
},
"limit": {
"type": "integer",
"description": "Maximum books to return. Defaults to 5, maximum 10.",
},
},
},
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free-form book search query, such as a title, author, topic, or ISBN.",
},
"author": {
"type": "string",
"description": "Optional author name filter.",
},
"subject": {
"type": "string",
"description": "Optional subject filter, such as science fiction or product management.",
},
"limit": {
"type": "integer",
"description": "Maximum books to return. Defaults to 5, maximum 10.",
},
},
"description": "At least one of query, author, or subject must be provided.",
},

@absalonCRC
Copy link
Copy Markdown
Author

Addressed the Greptile quality feedback in commit 0348468:

  • added schema-level anyOf requirements for search_books so callers provide query, author, or subject
  • added schema-level anyOf requirements for get_book_details so callers provide work_id or ISBN
  • added friendly 404 handling for unknown Open Library subject lookups

Validation rerun with the app pinned Python 3.11 deps:

  • plugins/omi-open-library-app/.venv/bin/python -m py_compile plugins/omi-open-library-app/main.py
  • git diff --check
  • FastAPI TestClient manifest checks for all 3 tools and the new anyOf schema constraints
  • helper checks for string/invalid limits, work IDs, ISBN cleanup, and subject slugs
  • live Open Library smoke checks for search_books, get_book_details, and search_subject
  • mocked HTTP 404 check for search_subject friendly missing-subject response

Copy link
Copy Markdown
Collaborator

@kodjima33 kodjima33 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for adding the Open Library app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants