Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 134 additions & 61 deletions api/oss/src/dbs/postgres/tracing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1284,9 +1284,16 @@ def build_numeric_continuous_blocks(
(cont_minmax.c.vmax_opt.isnot(None), cast(cont_minmax.c.vmax_opt, Numeric)),
else_=cont_minmax.c.vmax,
)
chosen_bins = case(
(cont_minmax.c.bins_opt.isnot(None), cast(cont_minmax.c.bins_opt, Integer)),
else_=cast(func.ceil(func.sqrt(cast(cont_minmax.c.n, Numeric))), Integer),
# Guard against bins <= 0 (pre-existing: MetricSpec.bins has no lower bound).
chosen_bins = func.greatest(
case(
(
cont_minmax.c.bins_opt.isnot(None),
cast(cont_minmax.c.bins_opt, Integer),
),
else_=cast(func.ceil(func.sqrt(cast(cont_minmax.c.n, Numeric))), Integer),
),
literal(1, type_=Integer),
)

cont_bins = (
Expand All @@ -1308,83 +1315,149 @@ def build_numeric_continuous_blocks(
).cte("cont_bins")

# -------------------------------------------------
# 7. Bin series & intervals (precompute is_last_bin)
# 7. Assign each row a bin via width_bucket (O(1) per row)
# -------------------------------------------------
cont_bin_series = (
func.generate_series(1, cont_bins.c.bins)
.table_valued("bin")
.render_derived(name="cont_bin_series")
)
# width_bucket(value, vmin, vmax, bins) returns 1..bins for values
# in [vmin, vmax). Values exactly equal to vmax land in bin (bins+1),
# so we nudge the upper bound by a tiny epsilon to keep them inside.
# This replaces the previous generate_series + nested-loop-join approach
# which was O(N * sqrt(N)).

# To handle edge vs center alignment:
# edge=True (default): bins span [vmin, vmax] evenly.
# edge=False: bin centers span [vmin, vmax]; edges extend
# by half a bin-width on each side.
# In both cases width_bucket operates on an adjusted range so that the
# bin assignment is correct.

is_edge_aligned = cont_bins.c.edge.is_(None) | cont_bins.c.edge.is_(True)

bin_width = case(
(is_edge_aligned, (cont_bins.c.vmax - cont_bins.c.vmin) / cont_bins.c.bins),
else_=(cont_bins.c.vmax - cont_bins.c.vmin) / (cont_bins.c.bins - 1),
# For edge-aligned: range is [vmin, vmax], width = (vmax-vmin)/bins
# For center-aligned: range is [vmin - w/2, vmax + w/2]
# where w = (vmax-vmin)/(bins-1)
edge_width = (cont_bins.c.vmax - cont_bins.c.vmin) / cont_bins.c.bins
center_width = case(
(
cont_bins.c.bins > 1,
(cont_bins.c.vmax - cont_bins.c.vmin) / (cont_bins.c.bins - 1),
),
else_=cast(0, Numeric),
)

bin_intervals = (
select(
cont_bins.c.timestamp,
cont_bins.c.idx,
cont_bin_series.c.bin,
(cont_bin_series.c.bin == cont_bins.c.bins).label("is_last_bin"),
case(
(cont_bin_series.c.bin == literal(1, Integer), cont_bins.c.vmin),
else_=case(
(
is_edge_aligned,
cont_bins.c.vmin + (cont_bin_series.c.bin - 1) * bin_width,
),
else_=(cont_bins.c.vmin + (cont_bin_series.c.bin - 1) * bin_width)
- (bin_width / 2),
),
).label("interval_start"),
# width_bucket requires lo < hi. We only add epsilon when vmin == vmax
# (degenerate single-value case). For the normal case we keep wb_hi ==
# vmax so that internal bin boundaries stay exact, and clamp the overflow
# bucket (bins+1, where values == vmax land) back to the last bin via
# LEAST. This preserves the original [start, end) half-open semantics
# and avoids shifting boundary values for integer-valued metrics.
_ABS_EPS = cast(literal(1e-9), Numeric)

_is_degenerate = cont_bins.c.vmin == cont_bins.c.vmax

wb_lo = case(
(is_edge_aligned, cont_bins.c.vmin),
else_=cont_bins.c.vmin - center_width / 2,
)
wb_hi = case(
(
is_edge_aligned,
case(
(cont_bin_series.c.bin == cont_bins.c.bins, cont_bins.c.vmax),
else_=case(
(
is_edge_aligned,
cont_bins.c.vmin + cont_bin_series.c.bin * bin_width,
),
else_=(cont_bins.c.vmin + (cont_bin_series.c.bin - 1) * bin_width)
+ (bin_width / 2),
(_is_degenerate, cont_bins.c.vmax + _ABS_EPS),
else_=cont_bins.c.vmax,
),
),
else_=case(
(_is_degenerate, cont_bins.c.vmax + _ABS_EPS),
else_=cont_bins.c.vmax + center_width / 2,
),
)

cont_bucketed = (
select(
cont_raw.c.timestamp,
cont_raw.c.idx,
# Clamp overflow bucket (bins+1) to the last bin so that values
# exactly equal to vmax are counted in bin N, not lost.
func.least(
func.width_bucket(
cont_raw.c.value,
wb_lo,
wb_hi,
cont_bins.c.bins,
),
).label("interval_end"),
).select_from(cont_bins.join(cont_bin_series, literal(True)))
).cte("bin_intervals")
cont_bins.c.bins,
).label("bin"),
).select_from(
cont_raw.join(
cont_bins,
(cont_raw.c.timestamp == cont_bins.c.timestamp)
& (cont_raw.c.idx == cont_bins.c.idx),
)
)
).cte("cont_bucketed")

# -------------------------------------------------
# 8. Bin counts (use is_last_bin for <= on last bin)
# 8. Bin counts via GROUP BY (O(N) scan)
# -------------------------------------------------
cont_bin_counts = (
select(
cont_raw.c.timestamp,
cont_raw.c.idx,
bin_intervals.c.bin,
cont_bucketed.c.timestamp,
cont_bucketed.c.idx,
cont_bucketed.c.bin,
func.count().label("count"),
).group_by(
cont_bucketed.c.timestamp,
cont_bucketed.c.idx,
cont_bucketed.c.bin,
)
.select_from(
cont_raw.join(
bin_intervals,
(cont_raw.c.timestamp == bin_intervals.c.timestamp)
& (cont_raw.c.idx == bin_intervals.c.idx)
& (cont_raw.c.value >= bin_intervals.c.interval_start)
& case(
(
bin_intervals.c.is_last_bin,
cont_raw.c.value <= bin_intervals.c.interval_end,
),
else_=(cont_raw.c.value < bin_intervals.c.interval_end),
),
)
)
.group_by(cont_raw.c.timestamp, cont_raw.c.idx, bin_intervals.c.bin)
).cte("cont_bin_counts")

# -------------------------------------------------
# 9. Full histogram (includes empty bins)
# 9. Full histogram with interval boundaries
# -------------------------------------------------
# Generate the full bin series so that empty bins appear in the output.
cont_bin_series = (
func.generate_series(1, cont_bins.c.bins)
.table_valued("bin")
.render_derived(name="cont_bin_series")
)

# Reuse the widths computed in step 7 for interval boundaries.
bin_width = case(
(is_edge_aligned, edge_width),
else_=center_width,
)

interval_start = case(
(cont_bin_series.c.bin == literal(1, Integer), cont_bins.c.vmin),
else_=case(
(
is_edge_aligned,
cont_bins.c.vmin + (cont_bin_series.c.bin - 1) * bin_width,
),
else_=(cont_bins.c.vmin + (cont_bin_series.c.bin - 1) * bin_width)
- (bin_width / 2),
),
)
interval_end = case(
(cont_bin_series.c.bin == cont_bins.c.bins, cont_bins.c.vmax),
else_=case(
(is_edge_aligned, cont_bins.c.vmin + cont_bin_series.c.bin * bin_width),
else_=(cont_bins.c.vmin + (cont_bin_series.c.bin - 1) * bin_width)
+ (bin_width / 2),
),
)

bin_intervals = (
select(
cont_bins.c.timestamp,
cont_bins.c.idx,
cont_bin_series.c.bin,
interval_start.label("interval_start"),
interval_end.label("interval_end"),
).select_from(cont_bins.join(cont_bin_series, literal(True)))
).cte("bin_intervals")

full_hist = (
select(
bin_intervals.c.timestamp,
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/reference/api/create-workspace.api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Create Workspace"
sidebar_label: "Create Workspace"
hide_title: true
hide_table_of_contents: true
api: eJzdWN1v2zYQ/1eMe9owNXa8pcX0tKwt0KDraqTp+mAEAiOdbTYUqZJUXM/w/z4cKYmU/JEs2NPyEvF43/fj8egtqAo1s1zJqwJSyDUyi9la6XtTsRwhgYppVqJFbSCdb0GyEiEFpZdM8r+dZMYLSIBLSKFidgUJaPxWc40FpFbXmIDJV1gySLdgNxWJG6u5XEIClltBhI+RvtFVAbvdrVeDxv6uig3JDrXmSlqUlrZYVQmeO+nxV6Mk0YLRSlOUlqOhlY9gC0xuPi5cTH2ndklHkbUQQJ60bv5JsrsECjS55hXZe66qN5GKXdKwPU/VDdF3nRJQd18xt1F2X7uyfumqutsRt0ZTKWl8VqaTCf3rBQaf6jxHYxa1GF03zPDsvHtsFRmzp4DgXS1Gl+R/gQtWCwspTCfTly8m0xfTl6Ppz+nFq/R8enZ+cT69ePXTZJJOJpTCuiqeYOCz53qqgV8vggFenFJMqE3+t+hKekf+qUeZ5Eos71z3iM1zi6XZx0htUDvGouAkz8Qs2vfH/hjIP5MswVoJr+yIDdrP2jINg0BZl5DOQa0lakjggePafWDBrXIfD0zUzH93fTJjRcmlA1Ql1KZEabOSSbZEDVEquxN4rQS2vmb/QblJ32hQ8wp1yY3hSh7L/bHgNbIiMxtjsWxSkEUH3TTZiGnUFfzVwaoqe2CaM+nPl8A9YqkKvti0hCxXcsGXte6UB6FWfSSsa5kZ1A/cXU7ON4O5Rtt61a38XsWCw+3C7SyUKAiWzV5YNvHy7B43Uazdus1HhvKBayVdsUPdo+wc54iSdZTH2bForAnBhWWjIRCarAWCk2/Q6ktEuQuELrYeT6O3R2tUD2jk6gADzmQ8PDj9MeHAgNFoj0kNQqgbZP44J9QSMolrT7Rq30yvP3VqB9ShlsG2RoM2q5gxa6WLNqI7LkRzQshQWHbxLoRamzjelkApj9dxUZQelkAFAEawCFx9WlOCAdVJf6tRc+wEwzIGlRmgKoBbSmUHZ71HclxcPqhBR+iTBgDMdH0Icy15yG1ylExzdUgk3tuzgqYW9qChbmcoU6LVPD8kE3aGMt9qrPGQSLfhc62UCIluFoQK/x318FnXr8ONDUxrtjnZ+mdRmz80A4apeR5dfYcupRMO9G+axw25e7y9ig/Z+uCGgm6o/DcBf2jmicd8cK8SxzCYXQ5eyJ0nbjT+ZTrdn4b/YoIX/oXyVms3ADxzFC7QMi5OzChC5b3dJ8wEXFqkcWN3e7x4fzSn041lZnlqivuAxrAlxsPjMVaXjFE7JnJZ1X4Ab+diR9glkNvvkZr9Rwrl8rt9tK6UG+9+wxfVM5TIV+h4Kt74Epx6Nb27uZntKfT46APDv1lGX+IbDO1K0Yu6Usa6V7RdQQrjGIhmvB08o3fj7lajNkFzTvvurrWAFFbWViYdj3Oh6uKMLVFadsb4mFXcnRGDea253TiRy9nVe9y8Q1bQUD2/jRk+ETI91vpsXX1Yxd8jZax58V/WdqV0uCrde3/lpSglhPnr8GB/+52VlcDw4A646ScvwGmAbOByoWIgXbpwR5ezK2quqI1XMDk7P5vsqe0x0zFluY2c8duQDPLaZZQ6dunOKFhk5W9hg2KlopZMRvoOQGAw1jfhEcTHlWDcHUJnfdugY95rUwSAdP9nlgggtwmsCF3pHLbbO2bwsxa7HZHpvicM3CbgJuc7yt98CwU39F1AumDC4J6PXTuDH66bE/fjKJSm73uLE0kgoeuPVpDAPW4O/EDk2tKqxeK24XrtDb648W261bLXS6nPeYnLPMfKnuS9jY7f7OOnG0jgrvkJqVQFyWi2pqbC1t5jVdn2leRoWxBMLmtqfyl4nfT3Dz31vYQ=
api: eJzdWN1v2zYQ/1eMe9owNfbcruj0tKwt0KDraqTp+mAEAiOdbbYUqZJUXM/Q/z4cKYmU/NEs2NPyEvF43/fj8eg9qAo1s1zJqwJSyDUyi9lW6S+mYjlCAhXTrESL2kC63INkJUIKSq+Z5H87yYwXkACXkELF7AYS0Pi15hoLSK2uMQGTb7BkkO7B7ioSN1ZzuYYELLeCCO8jfZOrAprm1qtBY39XxY5kx1pzJS1KS1usqgTPnfT0s1GSaMFopSlKy9HQykewByZ371cupqFTTdJTZC0EkCedm3+SbJNAgSbXvCJ7j1X1KlLRJC3b41TdEL3plYC6+4y5jbL70pX1U1/VpiFujaZS0viszGcz+jcIDD7UeY7GrGoxuW6Z4dF599gqMmbPAcG7Wkwuyf8CV6wWFlKYz+bPn8zmT+YvJrOn6exF+svTi6cv5s9mv/40m6WzGaWwrooHGPjouR5q4Nk8GODFOcWE2uR/i65kcOQfepRJrsTyznWP2Dy3WJpDjNQGtWMsCk7yTCyifX/sT4H8I8kSrJXwyk7YoP2sK9M4CJR1CekS1FaihgTuOW7dBxbcKvdxz0TN/HffJzNWlFw6QFVC7UqUNiuZZGvUEKWyP4HXSmDna/YflJv0TUY1r1CX3Biu5KncnwpeIysyszMWyzYFWXTQTZuNmEZdwV8drKqye6Y5k/58CTwglqrgq11HyHIlV3xd6155EOrUR8K6lplBfc/d5eR8M5hrtJ1X/crvVSw43C3czkqJgmDZ7oVlGy/PvuAuirVfd/nIUN5zraQrdqh7lJ3THFGyTvI4OxaNNSG4sGw1BEKbtUBw8i1afYkod4HQxzbgafUOaK3qEY1cHWHAmYyHB6c/JhwZMFrtMalFCHWDzB/nhFpCJnHriVYdmhn0p17tiDrWMtrWaNBmFTNmq3TRRXTHhWhPCBkKyz7elVBbE8fbESjl8TouitLjEqgAwAgWgWtIa0swojrprzVqjr1gWMagMiNUBXBLqezorA9IjovLezXqCEPSCICZro9hriOPuU2OkmmujonEewdW0NTCHjXU74xlSrSa58dkws5Y5muNNR4T6Td8rpUSIdHtglDhv6Mevuj7dbixgWnNdmdb/yJq88dmwDA1L6Or79ildMaB4U3zfUPuHu+u4mO23rmhoB8q/03A79p54ns+uFeJYxjNLkcv5N4TNxo/m88Pp+G/mOCFf6G81toNAI8chQu0jIszM4pQ+WD3ATMBlxZp3GhuTxfvj/Z0urHMrM9Nce/QGLbGeHg8xeqSMenGRC6r2g/g3VzsCE0Cuf0WqTl8pFAuv9nv1pVy491v+aJ6hhL5Cp1OxStfgnOvpjc3N4sDhR4fQ2D4N8vkU3yDod0oelFXylj3irYbSGEaA9FM96NndDPtbzVqEzTndO/uWgtIYWNtZdLpNBeqLi7YGqVlF4xPWcXdGTGY15rbnRO5XFy9xd0bZAUN1cvbmOEDIdNjbcjW14dV/C1SxtoX/2VtN0qHq9K99zdeilJCmL8OD/bX31hZCQwP7oCbYfICnEbIBi5XKgbSpQt3crm4ouaK2ngFs4ufL2YHagfMdExZbiNn/DYko7z2GaWOXbozChZZ+VvYoFipqCWTkb4jEBiN9W14BPFpJRh3h9BZ37foWA7aFAEgPfyZJQLIbQIbQle6hP3+jhn8qEXTEJnue8LAbQJucr6j/C33UHBD3wWkKyYMHvjYtzP44bo9cT9OQmmGvnc4kQQSuv5oBQl8wd2RH4hcW9p0WNy3XC+9wSc3vk13Wg56KfU5L3GZ51jZs7y30fFbvP9wAwnctT8hlaogGc221FTY1nusKtu9khxtD4LJdU3tLwWvk/7+AbCtvYs=
sidebar_class_name: "post api-method"
info_path: reference/api/agenta-api
custom_edit_url: null
Expand Down Expand Up @@ -62,7 +62,7 @@ Create Workspace
<StatusCodes
id={undefined}
label={undefined}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"created_at":{"type":"string","title":"Created At","default":"2026-02-26 23:57:12.151257+00:00"},"updated_at":{"type":"string","title":"Updated At","default":"2026-02-26 23:57:12.151295+00:00"},"id":{"type":"string","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"organization":{"type":"string","title":"Organization"},"members":{"anyOf":[{"items":{"properties":{"user":{"additionalProperties":true,"type":"object","title":"User"},"roles":{"items":{"properties":{"role_name":{"type":"string","enum":["owner","viewer","editor","evaluator","workspace_admin","deployment_manager"],"title":"WorkspaceRole"},"role_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role Description"},"permissions":{"anyOf":[{"items":{"type":"string","enum":["read_system","view_applications","edit_application","create_app_variant","delete_app_variant","modify_variant_configurations","delete_application_variant","run_service","view_secret","edit_secret","view_spans","edit_spans","view_folders","edit_folders","view_api_keys","edit_api_keys","view_app_environment_deployment","edit_app_environment_deployment","create_app_environment_deployment","view_testset","edit_testset","create_testset","delete_testset","view_evaluation","run_evaluations","edit_evaluation","create_evaluation","delete_evaluation","deploy_application","view_workspace","edit_workspace","create_workspace","delete_workspace","modify_user_roles","add_new_user_to_workspace","edit_organization","delete_organization","add_new_user_to_organization","reset_password","view_billing","edit_billing","view_workflows","edit_workflows","run_workflows","view_evaluators","edit_evaluators","view_environments","edit_environments","deploy_environments","view_queries","edit_queries","view_testsets","edit_testsets","view_annotations","edit_annotations","view_invocations","edit_invocations","view_evaluation_runs","edit_evaluation_runs","view_evaluation_scenarios","edit_evaluation_scenarios","view_evaluation_results","edit_evaluation_results","view_evaluation_metrics","edit_evaluation_metrics","view_evaluation_queues","edit_evaluation_queues","view_tools","edit_tools","run_tools"],"title":"Permission"},"type":"array"},{"type":"null"}],"title":"Permissions"}},"type":"object","required":["role_name"],"title":"WorkspacePermission"},"type":"array","title":"Roles"}},"type":"object","required":["user","roles"],"title":"WorkspaceMemberResponse"},"type":"array"},{"type":"null"}],"title":"Members"}},"type":"object","required":["id","type","organization"],"title":"WorkspaceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
responses={{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"properties":{"created_at":{"type":"string","title":"Created At","default":"2026-02-28 03:08:53.382409+00:00"},"updated_at":{"type":"string","title":"Updated At","default":"2026-02-28 03:08:53.382442+00:00"},"id":{"type":"string","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"},"organization":{"type":"string","title":"Organization"},"members":{"anyOf":[{"items":{"properties":{"user":{"additionalProperties":true,"type":"object","title":"User"},"roles":{"items":{"properties":{"role_name":{"type":"string","enum":["owner","viewer","editor","evaluator","workspace_admin","deployment_manager"],"title":"WorkspaceRole"},"role_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role Description"},"permissions":{"anyOf":[{"items":{"type":"string","enum":["read_system","view_applications","edit_application","create_app_variant","delete_app_variant","modify_variant_configurations","delete_application_variant","run_service","view_secret","edit_secret","view_spans","edit_spans","view_folders","edit_folders","view_api_keys","edit_api_keys","view_app_environment_deployment","edit_app_environment_deployment","create_app_environment_deployment","view_testset","edit_testset","create_testset","delete_testset","view_evaluation","run_evaluations","edit_evaluation","create_evaluation","delete_evaluation","deploy_application","view_workspace","edit_workspace","create_workspace","delete_workspace","modify_user_roles","add_new_user_to_workspace","edit_organization","delete_organization","add_new_user_to_organization","reset_password","view_billing","edit_billing","view_workflows","edit_workflows","run_workflows","view_evaluators","edit_evaluators","view_environments","edit_environments","deploy_environments","view_queries","edit_queries","view_testsets","edit_testsets","view_annotations","edit_annotations","view_invocations","edit_invocations","view_evaluation_runs","edit_evaluation_runs","view_evaluation_scenarios","edit_evaluation_scenarios","view_evaluation_results","edit_evaluation_results","view_evaluation_metrics","edit_evaluation_metrics","view_evaluation_queues","edit_evaluation_queues","view_tools","edit_tools","run_tools"],"title":"Permission"},"type":"array"},{"type":"null"}],"title":"Permissions"}},"type":"object","required":["role_name"],"title":"WorkspacePermission"},"type":"array","title":"Roles"}},"type":"object","required":["user","roles"],"title":"WorkspaceMemberResponse"},"type":"array"},{"type":"null"}],"title":"Members"}},"type":"object","required":["id","type","organization"],"title":"WorkspaceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"}}}}}}
>

</StatusCodes>
Expand Down
Loading