Skip to content

[feat] Extend loadables#3811

Merged
junaway merged 45 commits intorelease/v0.92.0from
feat/extend-loadables-in-api
Mar 6, 2026
Merged

[feat] Extend loadables#3811
junaway merged 45 commits intorelease/v0.92.0from
feat/extend-loadables-in-api

Conversation

@jp-agenta
Copy link
Member

@jp-agenta jp-agenta commented Feb 23, 2026

PR: Loadables Retrieval Alignment

Summary

This PR aligns loadables retrieval behavior across testsets/queries, removes stale design drift in docs, and makes the traces router a first-class traces API (no tracing-shaped response types in traces endpoints).

Change Inventory

API: Testsets

  1. Fixed _populate_testcases(...) call-site argument binding bugs by switching to keyword arguments.
  2. Added deterministic ID-level windowing support for testset revision retrieval (order, next, limit) when enumerating testcase_ids.
  3. Kept revision retrieval semantics where include_testcases=true returns both testcases and testcase_ids.
  4. Updated /preview/testsets/revisions/retrieve caching policy to cache only when include_testcases=false.

API: Queries

  1. Extended query revision population to merge request pagination (next, limit) into stored windowing.
  2. Kept revision retrieval semantics where trace expansion can return both traces and trace_ids.
  3. Updated /preview/queries/revisions/retrieve caching policy to cache only when both include_trace_ids=false and include_traces=false.
  4. Added permission coupling: query revision retrieve with trace expansion requires trace-view permission in addition to query-view permission.

API: Traces Router

  1. Introduced traces-specific DTOs:
    • TraceResponse
    • TracesResponse
    • TracesQueryRequest
  2. Removed formatting from TracesQueryRequest.
  3. Forced /preview/traces/query to always return Agenta trace trees (never spans/opentelemetry formatting).
  4. Removed external TracingQuery request contract from TracesRouter.query_traces; traces endpoint now consumes only TracesQueryRequest.
  5. Added query permission coupling for ref-dereferenced traces query (query_ref, query_variant_ref, query_revision_ref).
  6. Added native traces router fetch handler (GET /preview/traces/{trace_id}) returning TraceResponse.

Docs

  1. Updated docs/designs/loadables/loadables.querying.strategies.md to include:
    • include-flag defaults
    • conditional caching behavior
    • permission coupling notes
    • windowing.next terminology
  2. Updated docs/designs/loadables/loadables.initial.specs.md examples from cursor to next.
  3. Removed redundant docs/designs/loadables/loadables.querying.gap-analysis.md after consolidating its useful content into the strategies document.

Behavior Summary

  1. Revision endpoints remain the control surface for ID/item expansion.
  2. Record endpoints (/preview/testcases, /preview/traces) remain record-returning endpoints without extra top-level ID arrays.
  3. Traces router now has a clean traces-only contract and response types.

Validation

  1. Formatting/lint:
    • cd api && ruff format && ruff check --fix
  2. Targeted e2e:
    • pytest -q oss/tests/pytest/e2e/tracing/test_traces_basics.py oss/tests/pytest/e2e/loadables/test_loadable_strategies.py
    • Result: 27 passed
  3. Broader e2e:
    • pytest -q oss/tests/pytest/e2e/testsets/test_testsets_basics.py oss/tests/pytest/e2e/testsets/test_testsets_queries.py oss/tests/pytest/e2e/testsets/test_testcases_basics.py oss/tests/pytest/e2e/tracing/test_spans_basics.py oss/tests/pytest/e2e/tracing/test_spans_queries.py
    • Result: 17 passed, 3 skipped (existing flaky skips)
  4. Full e2e suite:
    • pytest -q oss/tests/pytest/e2e
    • Result: 175 passed, 3 skipped

Open with Devin

@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Mar 6, 2026 10:09am

Request Review

@jp-agenta jp-agenta requested a review from ardaerzin February 23, 2026 19:36
@jp-agenta jp-agenta requested a review from mmabrouk February 23, 2026 20:06
@jp-agenta jp-agenta marked this pull request as ready for review February 23, 2026 20:07
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. Backend documentation Improvements or additions to documentation labels Feb 23, 2026
@jp-agenta
Copy link
Member Author

jp-agenta commented Feb 23, 2026

@ardaerzin the files that matters most:

  • docs/designs/loadables/loadables.querying.strategies.md
  • docs/designs/loadables/loadables.endpoints.specs.md

devin-ai-integration[bot]

This comment was marked as resolved.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2026

Railway Preview Environment

Preview URL https://gateway-production-9aa8.up.railway.app/w
Image tag pr-3811-73022fa
Status Failed
Railway logs Open logs
Logs View workflow run
Updated at 2026-03-06T10:23:14.125Z

Copy link
Member

@mmabrouk mmabrouk left a comment

Choose a reason for hiding this comment

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

Thanks @jp-agenta lgtm

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 23, 2026
@jp-agenta jp-agenta changed the title [chore] Extend loadables in api [feat] Extend loadables in api Feb 24, 2026
@jp-agenta jp-agenta marked this pull request as draft February 24, 2026 14:18
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 43 additional findings in Devin Review.

Open in Devin Review

@CLAassistant
Copy link

CLAassistant commented Mar 3, 2026

CLA assistant check
All committers have signed the CLA.

devin-ai-integration[bot]

This comment was marked as resolved.

@junaway junaway changed the base branch from release/v0.87.3 to release/v0.91.0 March 6, 2026 09:14
@junaway junaway changed the base branch from release/v0.91.0 to release/v0.92.0 March 6, 2026 10:08
@junaway junaway merged commit 5586bf9 into release/v0.92.0 Mar 6, 2026
8 of 9 checks passed
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 43 additional findings in Devin Review.

Open in Devin Review

Comment on lines +181 to +192
elif traces:
for spans_tree in traces.values():
if spans_tree.spans:
for span in spans_tree.spans.values():
if not isinstance(span, list):
_spans[span.span_id] = OTelSpan(
**span.model_dump(
mode="json",
exclude_none=True,
exclude_unset=True,
)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 ingest_spans silently drops list-typed spans from trace trees, causing data loss

When ingest_spans processes spans from the traces parameter (trace tree format), it skips list-typed span values at line 185: if not isinstance(span, list). In the OTelNestedSpans type (Dict[str, Union[SpansNode, List[SpansNode]]]), spans with duplicate names within a trace are stored as List[SpansNode]. These are valid spans that the downstream parse_spans_from_request (api/oss/src/core/tracing/utils/parsing.py:346-365) correctly handles (it extends raw_span_dtos for list-typed values). However, the pre-filtering at line 185 silently discards them before they reach that parser.

This affects all trace ingestion flows that use the traces parameter: TracesRouter.create_trace, TracesRouter.ingest_traces, and the legacy TracingRouter.create_trace / edit_trace. Any trace containing two or more spans with the same name will have those duplicate-named spans silently dropped.

Suggested change
elif traces:
for spans_tree in traces.values():
if spans_tree.spans:
for span in spans_tree.spans.values():
if not isinstance(span, list):
_spans[span.span_id] = OTelSpan(
**span.model_dump(
mode="json",
exclude_none=True,
exclude_unset=True,
)
)
elif traces:
for spans_tree in traces.values():
if spans_tree.spans:
for span in spans_tree.spans.values():
if isinstance(span, list):
for s in span:
_spans[s.span_id] = OTelSpan(
**s.model_dump(
mode="json",
exclude_none=True,
exclude_unset=True,
)
)
else:
_spans[span.span_id] = OTelSpan(
**span.model_dump(
mode="json",
exclude_none=True,
exclude_unset=True,
)
)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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

Labels

Backend documentation Improvements or additions to documentation feature lgtm This PR has been approved by a maintainer size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants