Thanks to visit codestin.com
Credit goes to github.com

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
7 changes: 6 additions & 1 deletion docs/ai-coder/ai-gateway/audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ not just what was called.

The sessions page (`http://<deployment-url>/ai-gateway/sessions`) lists all sessions in
reverse-chronological order. Each row shows the last prompt, initiator, provider,
client, token usage, thread count, and timestamp.
client, token usage, network calls, thread count, and timestamp.

The network calls column reports the total and blocked
[Agent Firewall](../agent-firewall/index.md) calls for the session. It shows
`No activity` when the session made no calls, and `Disabled` when the session
did not pass through Agent Firewall, so no network calls were monitored.

Select one to view its full details.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ export const MultipleSessions: Story = {
cache_read_input_tokens: 800 * (i + 1),
cache_write_input_tokens: 50 * (i + 1),
},
network_calls: [
{ total: 23, blocked: 2 },
{ total: 5, blocked: 1 },
{ total: 0, blocked: 0 },
undefined,
{ total: 150, blocked: 0 },
][i],
})),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const ListSessionsPageView: FC<ListSessionsPageViewProps> = ({
<TableHead className="text-nowrap">Provider</TableHead>
<TableHead className="text-nowrap">Client</TableHead>
<TableHead className="text-nowrap">In/Out Tokens</TableHead>
<TableHead className="text-nowrap">Network Calls</TableHead>
<TableHead className="flex items-center flex-nowrap gap-1">
Threads
<ThreadTooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,27 @@ export const LargeTokenCounts: Story = {
},
},
};

export const NetworkCallsBlocked: Story = {
args: {
session: {
...MockSession,
network_calls: { total: 23, blocked: 2 },
},
},
};

export const NoNetworkActivity: Story = {
args: {
session: {
...MockSession,
network_calls: { total: 0, blocked: 0 },
},
},
};

export const NetworkDisabled: Story = {
args: {
session: { ...MockSession, network_calls: undefined },
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { AIBridgeClientIcon } from "#/pages/AIBridgePage/icons/AIBridgeClientIcon";
import { AIBridgeProviderIcon } from "#/pages/AIBridgePage/icons/AIBridgeProviderIcon";
import { DATE_FORMAT, formatDateTime } from "#/utils/time";
import { NetworkCallBadges } from "../NetworkCallBadges";
import { TokenBadges } from "../TokenBadges";
import { getProviderDisplayName } from "../utils";

Expand Down Expand Up @@ -105,6 +106,9 @@ export const ListSessionsRow: FC<ListSessionsRowProps> = ({
/>
</div>
</TableCell>
<TableCell className="w-40">
<NetworkCallBadges summary={session.network_calls} />
</TableCell>
<TableCell className="w-32">
<Badge className="bg-surface-secondary align-end">
{session.threads}
Expand Down
73 changes: 73 additions & 0 deletions site/src/pages/AIBridgePage/NetworkCallBadges.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, screen, userEvent, waitFor } from "storybook/test";
import { NetworkCallBadges } from "./NetworkCallBadges";

const meta: Meta<typeof NetworkCallBadges> = {
title: "pages/AIBridgePage/NetworkCallBadges",
component: NetworkCallBadges,
};

export default meta;
type Story = StoryObj<typeof NetworkCallBadges>;

export const TotalAndBlocked: Story = {
args: {
summary: { total: 23, blocked: 2 },
},
};

export const NoBlocked: Story = {
args: {
summary: { total: 23, blocked: 0 },
},
};

export const NoActivity: Story = {
args: {
summary: { total: 0, blocked: 0 },
},
};

export const Disabled: Story = {
args: {
summary: undefined,
},
};

export const LargeCounts: Story = {
args: {
summary: { total: 12_480, blocked: 320 },
},
};

// Tabbing to the badges reveals the breakdown tooltip without a mouse.
export const TotalAndBlockedKeyboard: Story = {
args: {
summary: { total: 23, blocked: 2 },
},
play: async () => {
await userEvent.tab();
await waitFor(() => {
const tooltip = screen.getByRole("tooltip");
expect(tooltip).toHaveTextContent("Total calls");
expect(tooltip).toHaveTextContent("Blocked");
});
},
};

// Tabbing to the disabled indicator's info button and pressing Enter reveals
// the reason popover without a mouse.
export const DisabledKeyboard: Story = {
args: {
summary: undefined,
},
play: async () => {
await userEvent.tab();
await userEvent.keyboard("{Enter}");
await waitFor(() =>
expect(screen.getByRole("dialog")).toHaveTextContent(
"Network call monitoring was not active for this session.",
),
);
},
};
78 changes: 78 additions & 0 deletions site/src/pages/AIBridgePage/NetworkCallBadges.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { BanIcon } from "lucide-react";
import type { FC } from "react";
import type { AIBridgeSessionNetworkCallSummary } from "#/api/typesGenerated";
import { Badge } from "#/components/Badge/Badge";
import { InfoTooltip } from "#/components/InfoTooltip/InfoTooltip";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "#/components/Tooltip/Tooltip";

interface NetworkCallBadgesProps {
// summary is undefined when network call monitoring was not active for the
// session, which renders as "Disabled".
summary: AIBridgeSessionNetworkCallSummary | undefined;
}

export const NetworkCallBadges: FC<NetworkCallBadgesProps> = ({ summary }) => {
if (!summary) {
return (
<span className="inline-flex items-center gap-1 whitespace-nowrap text-content-secondary">
Disabled
<InfoTooltip message="Network call monitoring was not active for this session." />
</span>
);
}

if (summary.total === 0) {
return (
<span className="whitespace-nowrap text-content-secondary">
No activity
</span>
);
}

return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
aria-label="More info"
className="flex items-center whitespace-nowrap border-0 bg-transparent p-0 text-inherit"
>
<Badge size="sm" className="rounded-e-none">
{summary.total.toLocaleString("en-US")}
</Badge>
<Badge
size="sm"
svgSize="xs"
className="gap-0 bg-surface-tertiary rounded-s-none text-content-warning"
>
<BanIcon className="flex-shrink-0" />
{summary.blocked.toLocaleString("en-US")}
</Badge>
</button>
</TooltipTrigger>
<TooltipContent
side="top"
align="start"
className="text-sm font-normal"
>
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between gap-4">
<span className="text-content-secondary">Total calls</span>
<span>{summary.total.toLocaleString("en-US")}</span>
</div>
<div className="flex items-center justify-between gap-4">
<span className="text-content-secondary">Blocked</span>
<span>{summary.blocked.toLocaleString("en-US")}</span>
</div>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
};
4 changes: 4 additions & 0 deletions site/src/testHelpers/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5523,6 +5523,10 @@ export const MockSession: TypesGen.AIBridgeSession = {
cache_read_input_tokens: 980,
cache_write_input_tokens: 120,
},
network_calls: {
total: 23,
blocked: 2,
},
last_prompt: "But *can* I really fix it?",
last_active_at: "2026-03-09T10:28:15.03152Z",
};
Expand Down
Loading