Skip to content

feat: support configurable Jina Reader endpoints#6

Open
hexmSeeU wants to merge 4 commits into
InternScience:mainfrom
hexmSeeU:codex/custom-jina-reader-endpoint
Open

feat: support configurable Jina Reader endpoints#6
hexmSeeU wants to merge 4 commits into
InternScience:mainfrom
hexmSeeU:codex/custom-jina-reader-endpoint

Conversation

@hexmSeeU

Copy link
Copy Markdown

Background

WebFetch previously used the hosted Jina Reader endpoint exclusively. This PR adds support for configurable Reader-compatible endpoints, including locally deployed Reader services.

Changes

  • Add the JINA_READER_BASE_URL environment variable.
  • Preserve the existing https://r.jina.ai behavior when no custom endpoint is configured.
  • When a custom endpoint is configured:
    • JINA_KEY is no longer required.
    • Jina credentials are never forwarded to the custom service.
    • Failures do not silently fall back to the hosted Jina service.
  • Validate that custom endpoints are absolute HTTP(S) URLs.
  • Update required-environment validation, README, English and Chinese tutorials, and tool documentation.
  • Add regression coverage for endpoint selection, credential isolation, validation, and failure handling.

Testing

Relevant checks pass for:

  • Hosted Reader authentication with JINA_KEY
  • Custom Reader operation without JINA_KEY
  • Credential isolation for custom endpoints
  • Invalid endpoint handling
  • No hosted fallback after custom endpoint failures

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for configuring a custom Jina Reader endpoint via the JINA_READER_BASE_URL environment variable, making the JINA_KEY optional when a custom endpoint is used. The changes span documentation, environment templates, the WebFetch tool implementation, and associated edge-case tests. The review feedback highlights three key improvements: handling empty or whitespace-only values of JINA_READER_BASE_URL to gracefully fall back to the default hosted reader, removing the required is None restriction in missing_required_env to ensure consistent bypass behavior for JINA_KEY, and adding a test case to verify the fallback behavior for empty/whitespace endpoint configurations.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +34 to +40
def jina_reader_base_url() -> str:
raw_value = os.getenv(JINA_READER_BASE_URL_ENV)
base_url = DEFAULT_JINA_READER_BASE_URL if raw_value is None else raw_value.strip().rstrip("/")
parsed = urlparse(base_url)
if parsed.scheme.lower() not in {"http", "https"} or not parsed.netloc:
raise ValueError("JINA_READER_BASE_URL must be an absolute HTTP(S) URL.")
return base_url

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If JINA_READER_BASE_URL is defined as an empty string or whitespace in the .env file (e.g., JINA_READER_BASE_URL= or JINA_READER_BASE_URL=""), os.getenv returns "". Currently, jina_reader_base_url() only checks if raw_value is None to fall back to the default hosted reader. Consequently, an empty or whitespace-only value will be parsed as an invalid URL and raise a ValueError, causing WebFetch to fail.

We should treat empty or whitespace-only values as unset and fall back to DEFAULT_JINA_READER_BASE_URL.

Suggested change
def jina_reader_base_url() -> str:
raw_value = os.getenv(JINA_READER_BASE_URL_ENV)
base_url = DEFAULT_JINA_READER_BASE_URL if raw_value is None else raw_value.strip().rstrip("/")
parsed = urlparse(base_url)
if parsed.scheme.lower() not in {"http", "https"} or not parsed.netloc:
raise ValueError("JINA_READER_BASE_URL must be an absolute HTTP(S) URL.")
return base_url
def jina_reader_base_url() -> str:
raw_value = os.getenv(JINA_READER_BASE_URL_ENV)
if raw_value is None or not raw_value.strip():
return DEFAULT_JINA_READER_BASE_URL
base_url = raw_value.strip().rstrip("/")
parsed = urlparse(base_url)
if parsed.scheme.lower() not in {"http", "https"} or not parsed.netloc:
raise ValueError("JINA_READER_BASE_URL must be an absolute HTTP(S) URL.")
return base_url

Comment thread agent_base/utils.py
Comment on lines +85 to +90
def missing_required_env(required: Optional[tuple[str, ...]] = None) -> list[str]:
required_env = REQUIRED_ENV_VARS if required is None else required
missing = [key for key in required_env if not os.getenv(key, "").strip()]
if required is None and os.getenv("JINA_READER_BASE_URL", "").strip():
missing = [key for key in missing if key != "JINA_KEY"]
return missing

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The bypass logic for JINA_KEY is currently restricted to when required is None. If a caller explicitly passes REQUIRED_ENV_VARS (or any custom list containing "JINA_KEY"), the bypass won't be applied even if JINA_READER_BASE_URL is configured.

Removing the required is None restriction makes the function more robust and consistent.

Suggested change
def missing_required_env(required: Optional[tuple[str, ...]] = None) -> list[str]:
required_env = REQUIRED_ENV_VARS if required is None else required
missing = [key for key in required_env if not os.getenv(key, "").strip()]
if required is None and os.getenv("JINA_READER_BASE_URL", "").strip():
missing = [key for key in missing if key != "JINA_KEY"]
return missing
def missing_required_env(required: Optional[tuple[str, ...]] = None) -> list[str]:
required_env = REQUIRED_ENV_VARS if required is None else required
missing = [key for key in required_env if not os.getenv(key, "").strip()]
if os.getenv("JINA_READER_BASE_URL", "").strip():
missing = [key for key in missing if key != "JINA_KEY"]
return missing

Comment on lines +2428 to +2431
os.environ["JINA_READER_BASE_URL"] = "file:///tmp/reader"
calls_before_invalid = len(calls)
invalid = WebFetch().jina_readpage("https://example.com/invalid")
invalid_made_request = len(calls) != calls_before_invalid

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To ensure that empty or whitespace-only values of JINA_READER_BASE_URL are correctly treated as unset and fall back to the hosted reader, we should add a test case to this function.

For example, we can set os.environ["JINA_READER_BASE_URL"] = " " and verify that it successfully falls back to https://r.jina.ai and includes the Authorization header.

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.

1 participant