Skip to content

'fix(sdk): anchor /api path stripping in init.py and tracing.py to avoid corrupting host named api - #6806

Open
mihsanalam wants to merge 7 commits into
Agenta-AI:mainfrom
mihsanalam:fix/6787-sdk-api-url-host-parsing
Open

mihsanalam wants to merge 7 commits into
Agenta-AI:mainfrom
mihsanalam:fix/6787-sdk-api-url-host-parsing

Conversation

@mihsanalam

@mihsanalam mihsanalam commented Sep 13, 2026

Copy link
Copy Markdown

Summary

Fixes #6787.

AgentaSingleton.init() derived the SDK's host from the API URL using
_api_url.rsplit("/api", 1)[0] — a plain string split that matches /api
anywhere in the URL, not just as a path segment. For an internal base URL
whose host is literally api (e.g. http://api:8000), this matches the
//api inside the scheme/host itself, corrupting the result and dropping
the port. The trace endpoint built from self.host then points at the
wrong address, causing the runner to reject it and every turn to fail.

While fixing this, I found the same bug pattern (matching /api as a
substring instead of anchoring to a path segment) in tracing.py's
get_trace_url(), which used .replace("/api", "") — actually more
prone to corruption than the original rsplit, since .replace strips
every occurrence, not just the last.

The fix extracts a shared strip_trailing_api_segment() helper into
helpers.py, which parses the URL properly with urlsplit/urlunsplit
and only strips a trailing /api path segment, leaving scheme/host/port
(parts.netloc) untouched regardless of what the host is named. Both
init.py and tracing.py now use this single helper instead of two
separate ad-hoc string manipulations. It also fixes a related edge case
found during testing: the original logic in both places silently dropped
any query string or fragment on the URL — the helper now preserves them.

Testing

Verified locally

  • Added 10 parametrized test cases for the helper directly, covering the
    reported host (api:8000), a similarly-named host (agenta-api:8000),
    a normal cloud host, and trailing-slash / query-string / fragment edge
    cases.
  • Added 6 parametrized test cases for AgentaSingleton.init()'s host
    derivation, plus a regression test confirming get_trace_url() no
    longer corrupts a host named api.
  • Ran the full unit suite: 4 failed, 2803 passed, 4 skipped, 3 xfailed.
    The only 4 failures are the same pre-existing, unrelated ones (litellm
    model-ID snapshot drift, a Windows CLI-streaming quirk, and benchmark
    markdown encoding), confirmed identical on a clean checkout of main
    before this change.
  • ruff format and ruff check pass on all changed files with no new
    issues introduced.

Added or updated tests

  • New file: sdks/python/oss/tests/pytest/unit/test_helpers.py
  • Updated: sdks/python/oss/tests/pytest/unit/test_init_singleton.py

QA follow-up

N/A

Demo

Before (main) — host is corrupted, port dropped:
image

After (this branch) — host and port preserved correctly:
image

@vercel

vercel Bot commented Sep 13, 2026

Copy link
Copy Markdown

@mihsanalam is attempting to deploy a commit to the agenta projects Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Sep 13, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions

github-actions Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

✅ Thanks @mihsanalam! This PR now meets the contribution requirements and has been reopened. A maintainer will review it soon.

@github-actions github-actions Bot added the incomplete-pr PR is missing required template sections or a demo recording label Sep 13, 2026
@github-actions github-actions Bot closed this Sep 13, 2026
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 950bbad9-7d6e-46ad-8362-26117181e3b0

📥 Commits

Reviewing files that changed from the base of the PR and between 293887f and b08cbd0.

📒 Files selected for processing (2)
  • sdks/python/agenta/sdk/utils/helpers.py
  • sdks/python/oss/tests/pytest/unit/test_init_singleton.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdks/python/agenta/sdk/utils/helpers.py

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes

    • Fixed API URL handling for trailing /api paths without altering valid hostnames, ports, versioned paths, or telemetry endpoints.
    • Removed query strings, fragments, and unnecessary trailing slashes from generated project, telemetry, and trace URLs.
    • Improved trace links and SDK host detection across supported endpoint formats.
  • Tests

    • Added coverage for URL parsing, host detection, scope resolution, and trace URL generation, including regression cases for query strings, fragments, and hosts containing “api.”

Walkthrough

The SDK now anchors /api removal to the URL path and removes query strings and fragments from stored API URLs. Host, OTLP, web trace, and scope URLs use the normalized values. Regression tests cover affected URL forms.

Changes

API URL normalization

Layer / File(s) Summary
URL normalization helpers
sdks/python/agenta/sdk/utils/helpers.py, sdks/python/oss/tests/pytest/unit/test_helpers.py
Adds URL helpers that remove query and fragment components and strip only a trailing /api path segment. Tests cover trailing slashes, versioned paths, hostnames, query strings, fragments, and OTLP paths.
SDK URL integration and regression coverage
sdks/python/agenta/sdk/utils/init.py, sdks/python/agenta/sdk/engines/tracing/tracing.py, sdks/python/oss/tests/pytest/unit/test_init_singleton.py
Uses anchored /api handling for host and trace URL derivation. Stores query-free API URLs for OTLP, web trace, and scope request construction. Tests cover hosts named api, query-bearing URLs, host-only inputs, and scope resolution.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to c5997

The SDK now preserves API hosts and ports while normalizing trailing API paths, with tests covering the affected request URLs. The change is ready to merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.15% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 27 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #6787 requires removal of only a trailing /api path segment while preserving the scheme, hostname, and port. The PR adds strip_trailing_api_segment() with urlsplit() and urlunsplit(). `i…
Out of Scope Changes check ✅ Passed The changes remain within issue #6787. The shared URL helpers, initialization changes, tracing changes, scope-resolution URL handling, and focused regression tests all support correct API host and end…
Title check ✅ Passed The title clearly identifies the SDK fix: anchoring /api path stripping in init.py and tracing.py to prevent corruption when the host is named api.
Description check ✅ Passed The description directly explains the URL parsing bug, the shared helper implementation, the affected endpoints, and the added test coverage.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot removed the incomplete-pr PR is missing required template sections or a demo recording label Sep 13, 2026
@github-actions github-actions Bot reopened this Sep 13, 2026
@mihsanalam

Copy link
Copy Markdown
Author

@mmabrouk This is ready for review — I've added the demo and 2 commits covering both init.py and tracing.py. Let me know if the CI workflows need approval to run.

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks for the pr. i found one url edge case that needs a change before this is ready.

Comment thread sdks/python/agenta/sdk/utils/helpers.py Outdated
"""
parts = urlsplit(url)
path = parts.path.rstrip("/").removesuffix("/api")
return urlunsplit((parts.scheme, parts.netloc, path, parts.query, parts.fragment))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The preserved query or fragment makes both callers build the wrong URL when they append a path. For example, this returns https://cloud.agenta.ai?tenant=x; AgentaSingleton.init() then creates https://cloud.agenta.ai?tenant=x/api/otlp/v1/traces, whose parsed path is empty and whose query is tenant=x/api/otlp/v1/traces. get_trace_url() breaks the same way, and a fragment swallows the appended path too. Please either clear query/fragment when deriving the host/web base or join the new path through URL components, and add assertions for the final OTLP and trace-view URLs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch; confirmed the issue. Preserving query/fragment lets it swallow the appended path (e.g., /w/ws-1/p/proj-1/observability) into the query string instead. Reverted to dropping query/fragment in strip_trailing_api_segment(), added a docstring explaining why, and added two regression tests asserting the final OTLP and get_trace_url() URLs are correct with a query-bearing api_url. Verified both tests genuinely fail without the fix and pass with it. Pushed in mihsanalam@a1219e9

@coderabbitai coderabbitai Bot added the slop label Sep 14, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: c7410215-88d5-431f-97a4-422213dd1f90

📥 Commits

Reviewing files that changed from the base of the PR and between e269578 and a1219e9.

📒 Files selected for processing (5)
  • sdks/python/agenta/sdk/engines/tracing/tracing.py
  • sdks/python/agenta/sdk/utils/helpers.py
  • sdks/python/agenta/sdk/utils/init.py
  • sdks/python/oss/tests/pytest/unit/test_helpers.py
  • sdks/python/oss/tests/pytest/unit/test_init_singleton.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread sdks/python/agenta/sdk/utils/init.py
@mihsanalam

Copy link
Copy Markdown
Author

@mmabrouk This is ready for another look. CodeRabbit flagged a related issue on
self.api_url itself, the same bug class as what you caught, but affecting
request-building in resolve_scopes() and a few other call sites too. Fixed by
stripping query/fragment from self.api_url at init, covering all of them at once.
Details and verification in the CodeRabbit thread above.

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)
sdks/python/agenta/sdk/utils/init.py (1)

101-113: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Normalize host before constructing the fallback API URL

When api_url is omitted and host contains a query or fragment, parse_url() preserves it. The fallback then appends /api after that component. strip_query_and_fragment() removes the appended /api, and derived OTLP and scope URLs use incorrect paths. Strip the query and fragment from _host before appending /api.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 510c5332-cc93-4648-82c9-f1a15d659c31

📥 Commits

Reviewing files that changed from the base of the PR and between a1219e9 and c2c41a7.

📒 Files selected for processing (3)
  • sdks/python/agenta/sdk/utils/helpers.py
  • sdks/python/agenta/sdk/utils/init.py
  • sdks/python/oss/tests/pytest/unit/test_init_singleton.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • sdks/python/agenta/sdk/utils/helpers.py
  • sdks/python/agenta/sdk/utils/init.py
  • sdks/python/oss/tests/pytest/unit/test_init_singleton.py

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)
sdks/python/agenta/sdk/utils/init.py (1)

113-114: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The new query/fragment normalization preserves a trailing slash after the /api segment, so an API URL such as https://host/api/?tenant=x makes resolve_scopes() request /api//projects/current instead of /api/projects/current. Normalize the trailing /api/ form before storing self.api_url so scope resolution uses the canonical endpoint.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Advanced

Run ID: 46804b98-b145-468e-bce5-a520c6ac1631

📥 Commits

Reviewing files that changed from the base of the PR and between c2c41a7 and 293887f.

📒 Files selected for processing (2)
  • sdks/python/agenta/sdk/utils/init.py
  • sdks/python/oss/tests/pytest/unit/test_init_singleton.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@mihsanalam

Copy link
Copy Markdown
Author

Hi @mmabrouk just checking in. I've addressed every finding from your review and from CodeRabbit across several rounds, all with verified regression tests, and CodeRabbit's latest pass says the change is ready to merge. Let me know if there's anything else needed or if you have a moment to take another look. No rush if you're busy!

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SDK] Unanchored "/api" split in init.py breaks the trace endpoint for a host named api

3 participants