Skip to content
Open
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
38 changes: 25 additions & 13 deletions src/components/Agentic/IncidentDetails/AgentSummary/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { useMemo } from "react";
import { useParams } from "react-router";
import { useStableSearchParams } from "../../../../hooks/useStableSearchParams";
import {
useGetIncidentAgentEventsQuery,
useGetIncidentAgentsQuery
} from "../../../../redux/services/digma";
import { useGetIncidentAgentsQuery } from "../../../../redux/services/digma";
import type { IncidentAgentEvent } from "../../../../redux/services/types";
import { ThreeCirclesSpinner } from "../../../common/ThreeCirclesSpinner";
import { Spinner } from "../../../common/v3/Spinner";
import { AgentEventsList } from "../../common/AgentEventsList";
import { AgentEventList } from "../../common/AgentEventList";
import { mockedAgentEvents } from "../../common/AgentEventList/mockData";
import { useAutoScroll } from "../useAutoScroll";
import * as s from "./styles";

const REFRESH_INTERVAL = 10 * 1000; // in milliseconds

const agentEventsData: IncidentAgentEvent[] = mockedAgentEvents.filter(
(event) => event.type !== "human"
);

const isLoading = false;

export const AgentSummary = () => {
const params = useParams();
const incidentId = params.id;
Expand All @@ -28,13 +33,13 @@ export const AgentSummary = () => {
}
);

const { data: agentEventsData, isLoading } = useGetIncidentAgentEventsQuery(
{ incidentId: incidentId ?? "", agentId: agentId ?? "" },
{
pollingInterval: REFRESH_INTERVAL,
skip: !incidentId || !agentId
}
);
// const { data: agentEventsData, isLoading } = useGetIncidentAgentEventsQuery(
// { incidentId: incidentId ?? "", agentId: agentId ?? "" },
// {
// pollingInterval: REFRESH_INTERVAL,
// skip: !incidentId || !agentId
// }
// );

const isAgentRunning = useMemo(
() =>
Expand All @@ -52,7 +57,14 @@ export const AgentSummary = () => {
</s.LoadingContainer>
)}
{agentEventsData && (
<AgentEventsList events={agentEventsData} typeInitialEvents={false} />
<s.EventsContainer>
{agentEventsData && (
<AgentEventList
events={agentEventsData}
typeInitialEvents={false}
/>
)}
</s.EventsContainer>
)}
{isAgentRunning && <ThreeCirclesSpinner />}
</s.Container>
Expand Down
6 changes: 6 additions & 0 deletions src/components/Agentic/IncidentDetails/AgentSummary/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ export const ToolSummary = styled.summary`
export const ToolContent = styled.div`
padding: 16px;
`;

export const EventsContainer = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
`;
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { useState } from "react";
import { ChevronIcon } from "../../../../../common/icons/16px/ChevronIcon";
import { Direction } from "../../../../../common/icons/types";
import { forwardRef, useState, type ForwardedRef } from "react";
import { ChevronIcon } from "../../../common/icons/16px/ChevronIcon";
import { Direction } from "../../../common/icons/types";
import * as s from "./styles";
import type { AccordionProps } from "./types";

export const Accordion = ({ summary, content }: AccordionProps) => {
export const AccordionComponent = (
{ summary, content, className }: AccordionProps,
ref: ForwardedRef<HTMLDivElement>
) => {
const [isOpen, setIsOpen] = useState(false);

const handleSummaryClick = () => {
setIsOpen((prev) => !prev);
};

return (
<s.Container>
<s.Container className={className} ref={ref}>
<s.Summary onClick={handleSummaryClick}>
<s.IconContainer>
<ChevronIcon
Expand All @@ -27,3 +30,5 @@ export const Accordion = ({ summary, content }: AccordionProps) => {
</s.Container>
);
};

export const Accordion = forwardRef(AccordionComponent);
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import styled from "styled-components";

export const Container = styled.div`
border: 1px solid ${({ theme }) => theme.colors.v3.stroke.primary};
border: 1px solid ${({ theme }) => theme.colors.v3.stroke.dark};
border-radius: 8px;
flex-shrink: 0;
overflow: hidden;
`;

export const Summary = styled.div`
background-color: ${({ theme }) => theme.colors.v3.surface.secondary};
background: ${({ theme }) => theme.colors.v3.surface.secondary};
color: ${({ theme }) => theme.colors.v3.text.primary};
padding: 8px;
cursor: pointer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import type { ReactNode } from "react";
export interface AccordionProps {
summary: ReactNode;
content: ReactNode;
className?: string;
}
40 changes: 1 addition & 39 deletions src/components/Agentic/common/AgentChat/AgentChat.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useEffect, useState } from "react";
import { fn } from "storybook/test";
import { AgentChat } from ".";
import type { IncidentAgentEvent } from "../../../../redux/services/types";
import { mockedAgentEvents } from "../AgentEventList/mockData";

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof AgentChat> = {
Expand All @@ -19,45 +20,6 @@ export default meta;
type Story = StoryObj<typeof AgentChat>;

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
const mockedAgentEvents: IncidentAgentEvent[] = [
{
id: "1",
type: "human",
message: "Can you help me understand why my API response time is slow?",
agent_name: "user"
},
{
id: "2",
type: "token",
message: "Let me analyze your application's performance data...",
agent_name: "agent"
},
{
id: "3",
type: "token",
message:
"I've found several performance issues in your application:\n\n1. **Database Query Optimization**: Your user lookup queries are taking an average of 2.3 seconds\n2. **Memory Usage**: High memory allocation in the user service\n3. **Cache Misses**: 78% cache miss rate on user data\n\nWould you like me to suggest specific optimizations for any of these areas?",
agent_name: "agent"
},
{
id: "4",
type: "tool",
agent_name: "agent",
message:
'\n```json\n{\n "success": false,\n "blockers": "Limited tool access prevents thorough investigation of system-wide issues, infrastructure problems, service mesh configurations, and external dependencies. Need access to Kubernetes API, service mesh telemetry, network monitoring tools, and container logs.",\n "result": {\n "is_relevant": true,\n "objective_success": false,\n "blockers": "Limited tool access prevents thorough investigation of system-wide issues, infrastructure problems, service mesh configurations, and external dependencies. Need access to Kubernetes API, service mesh telemetry, network monitoring tools, and container logs.",\n "beyond_the_result": {\n "summary": "Unable to fully investigate alternative causes due to tool limitations, but analysis suggests potential issues in service mesh, network policies, or external dependencies",\n "description": "The investigation revealed a severe performance degradation (2650%) in the PipelineConnector Execute operation that has been ongoing for over 24 hours. While direct investigation was limited by tool access, the pattern and severity suggest potential issues with service mesh routing, network policies, cross-namespace communication, or external service dependencies rather than simple resource constraints.",\n "confidence_level": "30",\n "confidence_level_reason": "Limited tool access prevents thorough investigation of infrastructure and network-related causes. The assessment is based primarily on timing patterns and service impact analysis rather than direct evidence."\n },\n "next_steps_suggestions": "1. Request access to Kubernetes cluster information and API\\n2. Obtain access to service mesh telemetry and dashboard\\n3. Deploy network monitoring tools\\n4. Enable access to container logs\\n5. Once access is granted, conduct thorough analysis of namespace configurations, service mesh settings, network policies, and external service dependencies",\n "actions_taken": [\n {\n "action": "Gathered relevant objects",\n "action_execution_success": true,\n "action_command": "list_relevant_incident_objects",\n "resolution_success_status": "PARTIAL",\n "resolution_explanation": "Successfully identified the critical trace ID but couldn\'t gather infrastructure-related objects",\n "resolution_success_evidence": "Retrieved trace ID FB0C56FA98816BBBFBB934CCEDEA72E4 showing the performance degradation",\n "state_changes_confirmed_due_to_actions": "Confirmed existence of trace showing 2650% performance degradation in PipelineConnector Execute operation"\n },\n {\n "action": "Tracked relevant trace",\n "action_execution_success": true,\n "action_command": "track_incident_relevant_object",\n "resolution_success_status": "PARTIAL",\n "resolution_explanation": "Successfully tracked the critical trace ID for future reference",\n "resolution_success_evidence": "Trace ID FB0C56FA98816BBBFBB934CCEDEA72E4 was successfully tracked",\n "state_changes_confirmed_due_to_actions": "Added trace to tracked objects for future investigation"\n }\n ]\n }\n}\n```\n',
tool_name: "kubernetes_resolution_expert_tool",
mcp_name: "",
status: "success"
},
{
id: "5",
type: "token",
message:
"Here are my recommendations for optimizing your database queries:\n\n```sql\n-- Add an index on the email column\nCREATE INDEX idx_users_email ON users(email);\n\n-- Use prepared statements\nSELECT id, name, email FROM users WHERE email = ?\n```\n\nThis should reduce your query time from 2.3s to under 100ms.",
agent_name: "agent"
}
];

const EVENTS_CURSOR = 2;
const EVENTS_TIMEOUT = 2000;

Expand Down
4 changes: 2 additions & 2 deletions src/components/Agentic/common/AgentChat/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { sendUserActionTrackingEvent } from "../../../../utils/actions/sendUserActionTrackingEvent";
import { Chat } from "../../common/Chat";
import { trackingEvents } from "../../tracking";
import { AgentEventsList } from "../AgentEventsList";
import { AgentEventList } from "../AgentEventList";
import type { AgentChatProps } from "./types";

export const AgentChat = ({
Expand Down Expand Up @@ -42,7 +42,7 @@ export const AgentChat = ({
chatContent={
<>
{data && (
<AgentEventsList
<AgentEventList
key={conversationId}
events={data}
typeInitialEvents={typeInitialMessages}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MarkdownRenderer } from ".";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof MarkdownRenderer> = {
title:
"Agentic/common/AgentEventsList/AgentEvent/TypingMarkdown/MarkdownRenderer",
"Agentic/common/AgentEventList/AgentEvent/TypingMarkdown/MarkdownRenderer",
component: MarkdownRenderer,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { sendUserActionTrackingEvent } from "../../../../../utils/actions/sendUserActionTrackingEvent";
import { MagicWandIcon } from "../../../../common/icons/16px/MagicWandIcon";
import { trackingEvents } from "../../../tracking";
import { Accordion } from "./Accordion";
import { Accordion } from "../../Accordion";
import { AgentEventSection } from "../../AgentEventSection";
import * as s from "./styles";
import type { AgentEventProps } from "./types";
import { TypingMarkdown } from "./TypingMarkdown";
Expand All @@ -10,6 +11,8 @@ const TYPING_SPEED = 3; // in milliseconds per character

export const AgentEvent = ({
event,
index,
eventsCount,
onNavigateToIncident,
onEventTypingComplete,
isEventTypingRequired
Expand Down Expand Up @@ -75,6 +78,15 @@ export const AgentEvent = ({
Updated saved memory
</s.MemoryUpdateMessage>
);
case "section": {
const type =
index === 0
? "intro"
: index === eventsCount - 1
? "summary"
: undefined;
return <AgentEventSection data={event} type={type} index={index} />;
}
default:
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {

export interface AgentEventProps {
event: IncidentAgentEvent;
index: number;
eventsCount: number;
onNavigateToIncident?: () => void;
onEventTypingComplete: (id: string) => void;
isEventTypingRequired: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { useEffect, useMemo, useState } from "react";
import type { IncidentAgentEvent } from "../../../../redux/services/types";
import { AgentEvent } from "./AgentEvent";
import type { AgentEventsListProps, RenderState } from "./types";
import type { AgentEventListProps, RenderState } from "./types";

const isTypingEvent = (event: IncidentAgentEvent) =>
["ai", "token"].includes(event.type);

export const AgentEventsList = ({
export const AgentEventList = ({
events,
onNavigateToIncident,
typeInitialEvents
}: AgentEventsListProps) => {
}: AgentEventListProps) => {
const [initialVisibleCount] = useState(() =>
typeInitialEvents ? 0 : events.length
);
Expand Down Expand Up @@ -97,10 +97,12 @@ export const AgentEventsList = ({
[events, renderState.currentEventIndex]
);

return visibleEvents.map((event) => (
return visibleEvents.map((event, i) => (
<AgentEvent
key={event.id}
event={event}
index={i}
eventsCount={visibleEvents.length}
onNavigateToIncident={onNavigateToIncident}
onEventTypingComplete={handleEventTypingComplete}
isEventTypingRequired={shouldShowTypingForEvent(event.id)}
Expand Down
Loading
Loading