From 69088bde006a2cc28ddb3f8e20e325da59f83a60 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vega Date: Tue, 16 Jun 2026 11:18:30 +0200 Subject: [PATCH 1/7] fix(sdk): normalize chat_v0 output to the canonical Message shape chat_v0 returned the raw LiteLLM message, leaking provider-specific fields (provider_specific_fields, annotations) into outputs. Validate through the SDK Message model so the output is the canonical {role, content, name, tool_calls, tool_call_id}, matching what a hook/custom workflow returns. --- sdks/python/agenta/sdk/engines/running/handlers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdks/python/agenta/sdk/engines/running/handlers.py b/sdks/python/agenta/sdk/engines/running/handlers.py index fbc515674a..ac1174c9ad 100644 --- a/sdks/python/agenta/sdk/engines/running/handlers.py +++ b/sdks/python/agenta/sdk/engines/running/handlers.py @@ -2220,7 +2220,10 @@ async def chat_v0( message = response.choices[0].message # type: ignore - return message.model_dump(exclude_none=True) # type: ignore + # Normalize to the canonical Message shape (drops provider-specific fields). + return Message.model_validate(message.model_dump(exclude_none=True)).model_dump( + exclude_none=True + ) @instrument(ignore_inputs=["parameters"]) From 3bc43ae7e267fbc0922c035f324de205f6cbea50 Mon Sep 17 00:00:00 2001 From: Mahmoud Mabrouk Date: Wed, 17 Jun 2026 20:24:55 +0200 Subject: [PATCH 2/7] fix(frontend): cap sidebar banner queue --- .../components/SidebarBanners/state/atoms.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/web/oss/src/components/SidebarBanners/state/atoms.ts b/web/oss/src/components/SidebarBanners/state/atoms.ts index 6724400836..8697bd6e11 100644 --- a/web/oss/src/components/SidebarBanners/state/atoms.ts +++ b/web/oss/src/components/SidebarBanners/state/atoms.ts @@ -19,6 +19,13 @@ export const PRIORITY_ORDER: Record = { trial: 3, // Lowest priority - show after other banners are dismissed } +/** + * Maximum number of dismissible sidebar banners a user should have to clear. + * Apply this before dismissal filtering so older changelog entries do not + * backfill the sidebar after each close. + */ +export const MAX_DISMISSIBLE_SIDEBAR_BANNERS = 2 + /** * Persisted atom for dismissed banner IDs. * Uses localStorage to remember which banners the user has dismissed. @@ -107,8 +114,17 @@ export const activeBannersAtom = atom((get) => { export const visibleBannersAtom = atom((get) => { const allBanners = get(activeBannersAtom) const dismissedIds = get(dismissedBannerIdsAtom) + const sortedBanners = [...allBanners].sort( + (a, b) => PRIORITY_ORDER[a.type] - PRIORITY_ORDER[b.type], + ) + + const cappedDismissibleBanners = sortedBanners + .filter((banner) => banner.dismissible) + .slice(0, MAX_DISMISSIBLE_SIDEBAR_BANNERS) + + const nonDismissibleBanners = sortedBanners.filter((banner) => !banner.dismissible) - return allBanners + return [...cappedDismissibleBanners, ...nonDismissibleBanners] .filter((banner) => !dismissedIds.includes(banner.id)) .sort((a, b) => PRIORITY_ORDER[a.type] - PRIORITY_ORDER[b.type]) }) From f8034fe4a7ebe48eec564c2733db2cd6f09c6eeb Mon Sep 17 00:00:00 2001 From: junaway <7041392+junaway@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:59:36 +0000 Subject: [PATCH 3/7] v0.104.1 --- api/pyproject.toml | 2 +- api/uv.lock | 6 +++--- clients/python/pyproject.toml | 2 +- clients/python/uv.lock | 2 +- hosting/kubernetes/helm/Chart.yaml | 4 ++-- sdks/python/pyproject.toml | 2 +- sdks/python/uv.lock | 4 ++-- services/pyproject.toml | 2 +- services/uv.lock | 6 +++--- web/ee/package.json | 2 +- web/oss/package.json | 2 +- web/package.json | 2 +- web/packages/agenta-api-client/package.json | 2 +- 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index d35b5004b1..49b67d707e 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "api" -version = "0.104.0" +version = "0.104.1" description = "Agenta API" requires-python = ">=3.11,<3.14" authors = [ diff --git a/api/uv.lock b/api/uv.lock index caf5b6e239..46e0565926 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -8,7 +8,7 @@ resolution-markers = [ [[package]] name = "agenta" -version = "0.104.0" +version = "0.104.1" source = { editable = "../sdks/python" } dependencies = [ { name = "agenta-client" }, @@ -70,7 +70,7 @@ dev = [ [[package]] name = "agenta-client" -version = "0.104.0" +version = "0.104.1" source = { editable = "../clients/python" } dependencies = [ { name = "httpx" }, @@ -259,7 +259,7 @@ wheels = [ [[package]] name = "api" -version = "0.104.0" +version = "0.104.1" source = { virtual = "." } dependencies = [ { name = "agenta" }, diff --git a/clients/python/pyproject.toml b/clients/python/pyproject.toml index 3a2a8eb324..8c6f2dd026 100644 --- a/clients/python/pyproject.toml +++ b/clients/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agenta-client" -version = "0.104.0" +version = "0.104.1" description = "Fern-generated Python client for the Agenta API." requires-python = ">=3.11,<3.14" authors = [ diff --git a/clients/python/uv.lock b/clients/python/uv.lock index e1a385a8fb..bc64e2f822 100644 --- a/clients/python/uv.lock +++ b/clients/python/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.11, <3.14" [[package]] name = "agenta-client" -version = "0.104.0" +version = "0.104.1" source = { editable = "." } dependencies = [ { name = "httpx" }, diff --git a/hosting/kubernetes/helm/Chart.yaml b/hosting/kubernetes/helm/Chart.yaml index d38313fb77..1905796e59 100644 --- a/hosting/kubernetes/helm/Chart.yaml +++ b/hosting/kubernetes/helm/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: agenta description: A Helm chart for deploying Agenta (OSS or EE) on Kubernetes type: application -version: 0.104.0 -appVersion: "v0.104.0" +version: 0.104.1 +appVersion: "v0.104.1" keywords: - agenta - llm diff --git a/sdks/python/pyproject.toml b/sdks/python/pyproject.toml index e5ef492fb9..49333aad01 100644 --- a/sdks/python/pyproject.toml +++ b/sdks/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "agenta" -version = "0.104.0" +version = "0.104.1" description = "The SDK for agenta is an open-source LLMOps platform." readme = "README.md" requires-python = ">=3.11,<3.14" diff --git a/sdks/python/uv.lock b/sdks/python/uv.lock index aa2895ade4..37f42a9323 100644 --- a/sdks/python/uv.lock +++ b/sdks/python/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.11, <3.14" [[package]] name = "agenta" -version = "0.104.0" +version = "0.104.1" source = { editable = "." } dependencies = [ { name = "agenta-client" }, @@ -83,7 +83,7 @@ dev = [ [[package]] name = "agenta-client" -version = "0.104.0" +version = "0.104.1" source = { editable = "../../clients/python" } dependencies = [ { name = "httpx" }, diff --git a/services/pyproject.toml b/services/pyproject.toml index 20a4d1c799..8572ba45e7 100644 --- a/services/pyproject.toml +++ b/services/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "services" -version = "0.104.0" +version = "0.104.1" description = "Agenta Services (Chat & Completion)" requires-python = ">=3.11,<3.14" authors = [ diff --git a/services/uv.lock b/services/uv.lock index 4aa66882b9..e0b40277f3 100644 --- a/services/uv.lock +++ b/services/uv.lock @@ -8,7 +8,7 @@ resolution-markers = [ [[package]] name = "agenta" -version = "0.104.0" +version = "0.104.1" source = { editable = "../sdks/python" } dependencies = [ { name = "agenta-client" }, @@ -70,7 +70,7 @@ dev = [ [[package]] name = "agenta-client" -version = "0.104.0" +version = "0.104.1" source = { editable = "../clients/python" } dependencies = [ { name = "httpx" }, @@ -2378,7 +2378,7 @@ wheels = [ [[package]] name = "services" -version = "0.104.0" +version = "0.104.1" source = { virtual = "." } dependencies = [ { name = "agenta" }, diff --git a/web/ee/package.json b/web/ee/package.json index cfd9748b6d..c75047b2d3 100644 --- a/web/ee/package.json +++ b/web/ee/package.json @@ -1,6 +1,6 @@ { "name": "@agenta/ee", - "version": "0.104.0", + "version": "0.104.1", "private": true, "engines": { "node": "24.x" diff --git a/web/oss/package.json b/web/oss/package.json index ad5f9e31ed..118c6b6dc7 100644 --- a/web/oss/package.json +++ b/web/oss/package.json @@ -1,6 +1,6 @@ { "name": "@agenta/oss", - "version": "0.104.0", + "version": "0.104.1", "private": true, "engines": { "node": "24.x" diff --git a/web/package.json b/web/package.json index 92c533d843..2053606d57 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "agenta-web", - "version": "0.104.0", + "version": "0.104.1", "workspaces": [ "ee", "oss", diff --git a/web/packages/agenta-api-client/package.json b/web/packages/agenta-api-client/package.json index 88e8c6a0dc..e4566dcda4 100644 --- a/web/packages/agenta-api-client/package.json +++ b/web/packages/agenta-api-client/package.json @@ -1,6 +1,6 @@ { "name": "@agentaai/api-client", - "version": "0.104.0", + "version": "0.104.1", "private": true, "type": "module", "main": "./dist/index.js", From 3abf559899e43b9e696fa691a071246bbf8ccfc3 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Thu, 18 Jun 2026 21:25:06 +0600 Subject: [PATCH 4/7] fix(SessionDrawerContent): default-select the "Session" root node for better UX fix(SessionsTable): share page store to resolve session data correctly in table cells --- .../components/SessionDrawerContent.tsx | 5 ++++- .../components/SessionsTable/index.tsx | 14 +++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerContent.tsx b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerContent.tsx index 2bb7320975..606c3c05b5 100644 --- a/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerContent.tsx +++ b/web/oss/src/components/SharedDrawers/SessionDrawer/components/SessionDrawerContent.tsx @@ -23,7 +23,10 @@ interface TraceDrawerContentProps { } const SessionDrawerContent = ({onClose, onToggleWidth, isExpanded}: TraceDrawerContentProps) => { - const [selected, setSelected] = useState("") + // Default-select the "Session" root node so the tree opens with a selection + // instead of nothing highlighted. The root node's key is always "root", and + // selecting it is a no-op in handleSelect (it early-returns for "root"). + const [selected, setSelected] = useState("root") const {isLoading} = useSessionDrawer() if (isLoading) { return ( diff --git a/web/oss/src/components/pages/observability/components/SessionsTable/index.tsx b/web/oss/src/components/pages/observability/components/SessionsTable/index.tsx index 0d15650646..188b362b27 100644 --- a/web/oss/src/components/pages/observability/components/SessionsTable/index.tsx +++ b/web/oss/src/components/pages/observability/components/SessionsTable/index.tsx @@ -2,7 +2,7 @@ import {useCallback, useEffect, useMemo, useState} from "react" import {InfiniteVirtualTableFeatureShell} from "@agenta/ui/table" import type {TableFeaturePagination, TableScopeConfig} from "@agenta/ui/table" -import {useAtomValue, useSetAtom} from "jotai" +import {useAtomValue, useSetAtom, useStore} from "jotai" import dynamic from "next/dynamic" import {SessionDrawer} from "@/oss/components/SharedDrawers/SessionDrawer" @@ -49,6 +49,14 @@ const SessionsTable: React.FC = () => { resetSessionPages, } = useSessions() + // The per-session cells (Traces count, First input, metrics, …) read their + // data from page-level atoms keyed by session id (e.g. `sessionsSpansAtom`). + // Without this, the table mounts its rows inside an isolated Jotai store + // (`useIsolatedStore` when no `store` is passed), where those atoms are empty + // — so every cell renders 0/"-" even though the data is loaded in the page + // store. Sharing the page store lets the cells resolve the real data. + const store = useStore() + const isNewUser = useAtomValue(isNewUserAtom) const onboardingStorageUserId = useAtomValue(onboardingStorageUserIdAtom) const openDrawer = useSetAtom(openSessionDrawerWithUrlAtom) @@ -111,7 +119,7 @@ const SessionsTable: React.FC = () => { const isEmptyState = sessionIds.length === 0 && !isLoading return ( -
+
{ ) : ( + store={store} tableScope={tableScope} columns={columns} rowKey="session_id" pagination={pagination} - autoHeight={false} resizableColumns enableExport={false} useSettingsDropdown={false} From f7797af69cb18d360e71c233152a26eebd3d0414 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Thu, 18 Jun 2026 21:34:08 +0600 Subject: [PATCH 5/7] fix(SessionIdCell): adjust Tag styling for improved layout and alignment --- .../SessionsTable/components/Cells/SessionIdCell.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx b/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx index 0fcd143913..be8dc956e3 100644 --- a/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx +++ b/web/oss/src/components/pages/observability/components/SessionsTable/components/Cells/SessionIdCell.tsx @@ -4,7 +4,10 @@ import {Tag} from "antd" export const SessionIdCell = ({sessionId}: {sessionId: string}) => { return ( - + # {sessionId} From 1fe344b8e4e2297494e78c4ab27646036eaee383 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Thu, 18 Jun 2026 21:35:24 +0600 Subject: [PATCH 6/7] non --- web/oss/src/state/newObservability/atoms/queries.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/web/oss/src/state/newObservability/atoms/queries.ts b/web/oss/src/state/newObservability/atoms/queries.ts index 29b74ee98c..c63e3c1d85 100644 --- a/web/oss/src/state/newObservability/atoms/queries.ts +++ b/web/oss/src/state/newObservability/atoms/queries.ts @@ -509,15 +509,18 @@ export const sessionTraceCountAtomFamily = atomFamily((sessionId: string) => }), ) -// Sorted traces are required for time-based metrics (Start/End/Duration) -// We memoize this to avoid re-sorting for every time-related cell +// Sorted traces are required for time-based metrics (Start/End/Duration) and for +// the First input / Last output cells. Sort by `start_time` (falling back to +// `created_at`) to match the Session drawer's tree ordering +// (SessionTree sorts its "Trace N" nodes by start_time). Sorting by a different +// key here made the table's first/last trace diverge from the drawer's. const sessionSortedTracesAtomFamily = atomFamily((sessionId: string) => atom((get) => { const traces = get(sessionTracesAtomFamily(sessionId)) if (!traces.length) return [] - return [...traces].sort( - (a, b) => new Date(a.created_at || 0).getTime() - new Date(b.created_at || 0).getTime(), - ) + const sortKey = (t: (typeof traces)[number]) => + new Date(t.start_time || t.created_at || 0).getTime() + return [...traces].sort((a, b) => sortKey(a) - sortKey(b)) }), ) From d8405d54d7782aef0bb747995b984d5db71d5498 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vega Date: Fri, 19 Jun 2026 10:57:22 +0200 Subject: [PATCH 7/7] test(api): align default-workspace test with oldest-membership behavior get_default_workspace_id no longer prefers owner-role (multi-org: an invitee owns their own empty personal workspace). Update the stale test to assert the oldest membership wins regardless of role. Co-Authored-By: Claude Opus 4.8 (1M context) --- api/oss/tests/pytest/unit/services/test_db_manager.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/oss/tests/pytest/unit/services/test_db_manager.py b/api/oss/tests/pytest/unit/services/test_db_manager.py index 0e380438ef..8b93b80261 100644 --- a/api/oss/tests/pytest/unit/services/test_db_manager.py +++ b/api/oss/tests/pytest/unit/services/test_db_manager.py @@ -55,7 +55,9 @@ def _patch_core_session(monkeypatch, memberships): @pytest.mark.asyncio -async def test_get_default_workspace_id_prefers_owner_membership(monkeypatch): +async def test_get_default_workspace_id_ignores_owner_role(monkeypatch): + # Owner-role is NOT preferred: under multi-org an invitee owns their own + # empty personal workspace, so the oldest membership wins regardless of role. owner_workspace_id = uuid4() editor_workspace_id = uuid4() @@ -77,7 +79,7 @@ async def test_get_default_workspace_id_prefers_owner_membership(monkeypatch): workspace_id = await db_manager.get_default_workspace_id(str(uuid4())) - assert workspace_id == str(owner_workspace_id) + assert workspace_id == str(editor_workspace_id) @pytest.mark.asyncio