@nethru/kit 1.1.17 → 1.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,9 @@
1
1
  import React, { useMemo } from 'react';
2
- import { Box, keyframes } from '@mui/material';
2
+ import { Box, IconButton, keyframes, Stack, Tooltip } from '@mui/material';
3
3
  import MarkdownContent from "./content/MarkdownContent";
4
4
  import ToolContent from "./content/ToolContent";
5
5
  import { ToolContextProvider } from "./contexts/ToolContext";
6
+ import ReplayRoundedIcon from "@mui/icons-material/ReplayRounded";
6
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
8
  const slideIn = keyframes`
8
9
  from {
@@ -15,20 +16,43 @@ const slideIn = keyframes`
15
16
  }
16
17
  `;
17
18
  const ChatMessage = ({
18
- message
19
+ message,
20
+ retryable,
21
+ onRetry
19
22
  }) => {
20
23
  const textContent = useMemo(() => message.content.filter(c => c.type === 'text'), [message]);
21
- return /*#__PURE__*/_jsxs(Box, {
22
- sx: message.role === 'user' ? styles.messageUser : styles.messageAssistant,
23
- children: [/*#__PURE__*/_jsx(ToolContextProvider, {
24
- message: message,
25
- children: /*#__PURE__*/_jsx(ToolContent, {})
26
- }), textContent.map((item, index) => /*#__PURE__*/_jsx(Box, {
27
- sx: styles.contentItem,
28
- children: /*#__PURE__*/_jsx(MarkdownContent, {
29
- content: item.value
24
+ return /*#__PURE__*/_jsxs(Stack, {
25
+ gap: 0.5,
26
+ sx: {
27
+ ...styles.options.base,
28
+ ...(retryable && styles.options.hover)
29
+ },
30
+ children: [/*#__PURE__*/_jsxs(Box, {
31
+ sx: message.role === 'user' ? styles.messageUser : styles.messageAssistant,
32
+ children: [/*#__PURE__*/_jsx(ToolContextProvider, {
33
+ message: message,
34
+ children: /*#__PURE__*/_jsx(ToolContent, {})
35
+ }), textContent.map((item, index) => /*#__PURE__*/_jsx(Box, {
36
+ sx: styles.contentItem,
37
+ children: /*#__PURE__*/_jsx(MarkdownContent, {
38
+ content: item.value
39
+ })
40
+ }, index))]
41
+ }), /*#__PURE__*/_jsx(Stack, {
42
+ className: "chat-options",
43
+ direction: "row",
44
+ justifyContent: "flex-end",
45
+ children: /*#__PURE__*/_jsx(Tooltip, {
46
+ title: "\uC7AC\uC2DC\uB3C4",
47
+ children: /*#__PURE__*/_jsx(IconButton, {
48
+ onClick: onRetry,
49
+ size: "small",
50
+ children: /*#__PURE__*/_jsx(ReplayRoundedIcon, {
51
+ fontSize: "small"
52
+ })
53
+ })
30
54
  })
31
- }, index))]
55
+ })]
32
56
  });
33
57
  };
34
58
  export default ChatMessage;
@@ -72,5 +96,20 @@ const styles = {
72
96
  '&:last-child': {
73
97
  marginBottom: 0
74
98
  }
99
+ },
100
+ options: {
101
+ base: {
102
+ '& .chat-options': {
103
+ opacity: 0,
104
+ pointerEvents: 'none',
105
+ transition: 'opacity 0.15s ease'
106
+ }
107
+ },
108
+ hover: {
109
+ '&:hover .chat-options': {
110
+ opacity: 1,
111
+ pointerEvents: 'auto'
112
+ }
113
+ }
75
114
  }
76
115
  };
@@ -1,22 +1,29 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, useMemo } from 'react';
2
2
  import ChatMessage from './ChatMessage';
3
3
  import LoadingIndicator from './LoadingIndicator';
4
+ import { useChatContext } from "./contexts/ChatContext";
4
5
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
6
  const ChatMessages = ({
6
7
  messages,
7
8
  isLoading,
8
9
  chatContainerRef
9
10
  }) => {
11
+ const {
12
+ retrySend
13
+ } = useChatContext();
10
14
  useEffect(() => {
11
15
  if (messages.length === 0) return;
12
16
  const message = messages[messages.length - 1];
13
17
  //if(message.role === 'assistant') console.log(message);
14
18
  }, [messages.length]);
19
+ const lastUserIdx = useMemo(() => messages.findLastIndex(m => m.role === 'user'), [messages.length]);
15
20
  return /*#__PURE__*/_jsxs("div", {
16
21
  style: styles.container,
17
22
  ref: chatContainerRef,
18
23
  children: [messages.map((message, index) => /*#__PURE__*/_jsx(ChatMessage, {
19
- message: message
24
+ message: message,
25
+ retryable: !isLoading && index === lastUserIdx,
26
+ onRetry: _ => retrySend(message.content[0].value)
20
27
  }, index)), isLoading && /*#__PURE__*/_jsx(LoadingIndicator, {})]
21
28
  });
22
29
  };
@@ -28,7 +35,6 @@ const styles = {
28
35
  padding: '10px',
29
36
  display: 'flex',
30
37
  flexDirection: 'column',
31
- gap: '1rem',
32
38
  background: '#fcfcfd'
33
39
  }
34
40
  };
@@ -1,13 +1,15 @@
1
- import React, { useMemo } from "react";
1
+ import React, { useCallback, useMemo } from "react";
2
2
  import { Box, Stack } from '@mui/material';
3
3
  import { useToolContext } from "../contexts/ToolContext";
4
4
  import ColumnChartContent from "./wisecollector/ColumnChartContent";
5
5
  import StackedAreaChartContent from "./wisecollector/StackedAreaChartContent";
6
6
  import PieChartContent from "./wisecollector/PieChartContent";
7
7
  import PeriodCompareChartContent from "./wisecollector/PeriodCompareChartContent";
8
+ import StackedAreaTrendChartWithSelectContent from "./wisecollector/StackedAreaTrendChartWithSelectContent";
8
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
10
  const summaryToolNames = ['query-summary-by-container-id', 'query-summary-by-task-id'];
10
11
  const trendToolNames = ['query-trend-by-container-id', 'query-trend-by-task-id'];
12
+ const trendDetailToolNames = ['query-trend-detail-by-task-id'];
11
13
  export default function ToolContent() {
12
14
  const {
13
15
  kinds,
@@ -18,24 +20,49 @@ export default function ToolContent() {
18
20
  const summaryTools = useMemo(() => tools.filter(t => summaryToolNames.includes(t.name)), [tools]);
19
21
  const {
20
22
  periodTrendTools,
21
- trendTools
22
- } = useMemo(() => groupTools(hasCompare, tools), [tools]);
23
+ trendTools,
24
+ trendDetailTools
25
+ } = useMemo(() => groupBy(hasCompare, tools), [tools, hasCompare]);
23
26
  const toolCount = useMemo(() => summaryTools.length + periodTrendTools.length + trendTools.length + jsonTools.length, [summaryTools, periodTrendTools, trendTools, jsonTools]);
27
+ const taskType = useMemo(() => {
28
+ return tools.find(t => t.name === "search-task-by-keyword")?.result?.result[0]?.taskType;
29
+ }, [tools]);
30
+ const getSeriesKeyByTrend = useCallback(tools => {
31
+ return tools?.some(t => t.name === 'query-trend-by-container-id') ? 'containerId' : 'taskId';
32
+ }, []);
33
+ const getSeriesKeyBySummary = useCallback(tool => {
34
+ return tool.name === 'query-summary-by-container-id' ? 'containerId' : 'taskId';
35
+ }, []);
24
36
  return /*#__PURE__*/_jsxs(Stack, {
25
37
  gap: 5,
26
38
  marginBottom: toolCount > 0 ? 5 : 0,
27
39
  children: [hasCompare && summaryTools.length >= 2 ? /*#__PURE__*/_jsx(ColumnChartContent, {
28
- tools: summaryTools
40
+ tools: summaryTools,
41
+ seriesKeyFunc: getSeriesKeyBySummary
29
42
  }) : summaryTools.map((tool, index) => /*#__PURE__*/_jsx(PieChartContent, {
30
- tool: tool
43
+ tool: tool,
44
+ seriesKeyFunc: getSeriesKeyBySummary
31
45
  }, index)), periodTrendTools.map((tools, index) => /*#__PURE__*/_jsx(PeriodCompareChartContent, {
32
- tools: tools
46
+ tools: tools,
47
+ seriesKey: getSeriesKeyByTrend(tools)
33
48
  }, index)), trendTools.map((tools, index1) => {
34
49
  if (hasCompare && tools.length >= 2) return /*#__PURE__*/_jsx(StackedAreaChartContent, {
35
- tools: tools
50
+ tools: tools,
51
+ seriesKey: getSeriesKeyByTrend(tools)
36
52
  }, index1);else {
37
53
  return tools.map((tool, index2) => /*#__PURE__*/_jsx(StackedAreaChartContent, {
38
- tools: [tool]
54
+ tools: [tool],
55
+ seriesKey: getSeriesKeyByTrend([tool])
56
+ }, index2));
57
+ }
58
+ }), trendDetailTools.map((tools, index) => {
59
+ if (hasCompare && tools.length >= 2) return /*#__PURE__*/_jsx(StackedAreaTrendChartWithSelectContent, {
60
+ tools: tools,
61
+ selectKey: taskType
62
+ }, index);else {
63
+ return tools.map((tool, index2) => /*#__PURE__*/_jsx(StackedAreaTrendChartWithSelectContent, {
64
+ tools: [tool],
65
+ selectKey: taskType
39
66
  }, index2));
40
67
  }
41
68
  }), jsonTools.map((tool, index) => /*#__PURE__*/_jsxs(Box, {
@@ -54,15 +81,32 @@ export default function ToolContent() {
54
81
  }, index))]
55
82
  });
56
83
  }
84
+ function groupBy(hasCompare, tools) {
85
+ const trendTools = tools.filter(t => trendToolNames.includes(t.name));
86
+ const trendDetailTools = tools.filter(t => trendDetailToolNames.includes(t.name));
87
+ if (trendTools.length > 0 || trendDetailTools.length > 0) {
88
+ const groupedTrend = groupTools(hasCompare, trendTools);
89
+ const groupedTrendDetail = groupTools(hasCompare, trendDetailTools);
90
+ return {
91
+ periodTrendTools: groupedTrend.periodTrendTools,
92
+ trendTools: groupedTrend.tools,
93
+ trendDetailTools: groupedTrendDetail.tools
94
+ };
95
+ }
96
+ return {
97
+ periodTrendTools: [],
98
+ trendTools: [],
99
+ trendDetailTools: []
100
+ };
101
+ }
57
102
  function groupTools(hasCompare, tools) {
58
103
  const periodKey = t => `${t.arguments.from}~${t.arguments.to}`;
59
104
  const idMap = new Map();
60
105
  const periodMap = new Map();
61
106
  const used = new Set();
62
- const filtered = tools.filter(t => trendToolNames.includes(t.name));
63
107
  const periodTrendTools = [];
64
- if (hasCompare) {
65
- for (const tool of filtered) {
108
+ if (hasCompare && tools.every(t => !trendDetailToolNames.includes(t.name))) {
109
+ for (const tool of tools) {
66
110
  const id = tool.arguments.containerId ?? tool.arguments.taskId;
67
111
  if (!idMap.has(id)) idMap.set(id, []);
68
112
  idMap.get(id).push(tool);
@@ -78,7 +122,7 @@ function groupTools(hasCompare, tools) {
78
122
  }
79
123
  }
80
124
  }
81
- for (const tool of filtered) {
125
+ for (const tool of tools) {
82
126
  if (used.has(tool)) continue;
83
127
  const key = periodKey(tool);
84
128
  if (!periodMap.has(key)) periodMap.set(key, []);
@@ -86,7 +130,7 @@ function groupTools(hasCompare, tools) {
86
130
  }
87
131
  return {
88
132
  periodTrendTools,
89
- trendTools: Array.from(periodMap.values())
133
+ tools: Array.from(periodMap.values())
90
134
  };
91
135
  }
92
136
  const styles = {
@@ -4,7 +4,8 @@ import { formatDateRange } from "../../../../js/dateHelper";
4
4
  import ColumnChart from "../../../charts/ColumnChart";
5
5
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
6
6
  const ColumnChartContent = ({
7
- tools = []
7
+ tools = [],
8
+ seriesKeyFunc
8
9
  }) => {
9
10
  const {
10
11
  getName
@@ -17,12 +18,12 @@ const ColumnChartContent = ({
17
18
  marginBottom: '30px'
18
19
  },
19
20
  children: /*#__PURE__*/_jsx(ColumnChart, {
20
- data: toData(tools, getName)
21
+ data: toData(tools, seriesKeyFunc, getName)
21
22
  })
22
23
  })
23
24
  });
24
25
  };
25
- function toData(tools, getName) {
26
+ function toData(tools, seriesKeyFunc, getName) {
26
27
  const items = [];
27
28
  const hasConvert = tools.some(tool => {
28
29
  const result = tool?.result?.result;
@@ -30,13 +31,12 @@ function toData(tools, getName) {
30
31
  });
31
32
  tools.sort((a, b) => a.arguments.from.localeCompare(b.arguments.from)).forEach(tool => {
32
33
  const {
33
- containerId,
34
- taskId,
35
34
  from,
36
35
  to
37
36
  } = tool.arguments;
37
+ const seriesKey = seriesKeyFunc(tool);
38
38
  const item = {
39
- name: `<b>${getName(containerId, taskId)}</b> <span style="font-size:10px">(${formatDateRange(from, to)})</span>`,
39
+ name: `<b>${getName(tool.arguments[seriesKey])}</b> <span style="font-size:10px">(${formatDateRange(from, to)})</span>`,
40
40
  data: []
41
41
  };
42
42
  const result = Array.isArray(tool.result.result) ? reduce(tool.result.result) : tool.result.result;
@@ -7,12 +7,14 @@ import { formatDuration } from "../../../charts/Number";
7
7
  import { formatMinutes } from "../../../charts/Time";
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  export default function PeriodCompareChartContent({
10
- tools
10
+ tools,
11
+ seriesKey
11
12
  }) {
12
13
  const chartData = useMemo(() => toChartData(tools), [tools]);
13
14
  return /*#__PURE__*/_jsxs("div", {
14
15
  children: [/*#__PURE__*/_jsx(Title, {
15
- tools: tools
16
+ tools: tools,
17
+ seriesKey: seriesKey
16
18
  }), /*#__PURE__*/_jsx(PeriodCompareChart, {
17
19
  ...chartData,
18
20
  height: 220
@@ -20,18 +22,15 @@ export default function PeriodCompareChartContent({
20
22
  });
21
23
  }
22
24
  function Title({
23
- tools
25
+ tools,
26
+ seriesKey
24
27
  }) {
25
28
  const {
26
29
  getName
27
30
  } = useToolContext();
28
- const {
29
- containerId,
30
- taskId
31
- } = tools[0].arguments;
32
31
  return /*#__PURE__*/_jsx("div", {
33
32
  style: styles.title,
34
- children: getName(containerId, taskId)
33
+ children: getName(tools[0].arguments[seriesKey])
35
34
  });
36
35
  }
37
36
  function toChartData(tools) {
@@ -4,14 +4,16 @@ import { useToolContext } from "../../contexts/ToolContext";
4
4
  import { formatDateRange } from "../../../../js/dateHelper";
5
5
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  const PieChartContent = ({
7
- tool
7
+ tool,
8
+ seriesKeyFunc
8
9
  }) => {
9
10
  const width = useMemo(() => {
10
11
  return tool?.result?.result?.length < 3 ? 300 : undefined;
11
12
  }, []);
12
13
  return /*#__PURE__*/_jsxs("div", {
13
14
  children: [/*#__PURE__*/_jsx(Title, {
14
- tool: tool
15
+ tool: tool,
16
+ seriesKeyFunc: seriesKeyFunc
15
17
  }), /*#__PURE__*/_jsx("div", {
16
18
  style: styles.container,
17
19
  children: toData(tool).map((item, index) => /*#__PURE__*/_jsx(PieChart, {
@@ -22,21 +24,21 @@ const PieChartContent = ({
22
24
  });
23
25
  };
24
26
  const Title = ({
25
- tool
27
+ tool,
28
+ seriesKeyFunc
26
29
  }) => {
27
30
  const {
28
31
  getName
29
32
  } = useToolContext();
30
33
  const {
31
- containerId,
32
- taskId,
33
34
  from,
34
35
  to
35
36
  } = tool.arguments;
37
+ const seriesKey = seriesKeyFunc(tool);
36
38
  return /*#__PURE__*/_jsxs("div", {
37
39
  style: styles.title,
38
40
  children: [/*#__PURE__*/_jsx("div", {
39
- children: getName(containerId, taskId)
41
+ children: getName(tool.arguments[seriesKey])
40
42
  }), /*#__PURE__*/_jsxs("div", {
41
43
  style: styles.subtitle,
42
44
  children: ["(", formatDateRange(from, to), ")"]
@@ -4,35 +4,47 @@ import { isOneDay, isToday } from "../../../../js/dateHelper";
4
4
  import StackedAreaTrendChart from "../../../charts/StackedAreaTrendChart";
5
5
  import { jsx as _jsx } from "react/jsx-runtime";
6
6
  export default function StackedAreaChartContent({
7
- tools
7
+ tools,
8
+ seriesKey,
9
+ type = 'output',
10
+ ...props
8
11
  }) {
9
12
  const {
10
13
  getName
11
14
  } = useToolContext();
12
15
  return /*#__PURE__*/_jsx("div", {
13
16
  children: /*#__PURE__*/_jsx(StackedAreaTrendChart, {
14
- metrics: toMetrics(tools, getName),
15
- records: fillRecords(tools, toRecords(tools)),
17
+ metrics: toMetrics(tools, seriesKey, getName),
18
+ records: fillRecords(tools, toRecords(type, seriesKey, tools)),
16
19
  isDaily: isDaily(tools),
17
20
  xPlotIndex: xPlotIndex(tools),
18
21
  xAxisTickInterval: 4,
19
- height: 200
22
+ height: 200,
23
+ ...props
20
24
  })
21
25
  });
22
26
  }
23
- function toMetrics(tools, getName) {
24
- return tools.map(tool => ({
25
- id: tool.arguments.taskId,
26
- name: getName(tool.arguments.containerId, tool.arguments.taskId),
27
- type: 'NUMBER'
28
- }));
27
+ function toMetrics(tools, seriesKey, getName) {
28
+ const formatId = tool => `${tool.arguments.agentId} - ${tool.arguments.taskId}`;
29
+ const formatName = tool => `${getName(tool.arguments.agentId)} - ${getName(tool.arguments.taskId)}`;
30
+ if (isAgentId(seriesKey)) {
31
+ return tools.map(tool => ({
32
+ id: formatId(tool),
33
+ name: formatName(tool),
34
+ type: 'NUMBER'
35
+ }));
36
+ } else {
37
+ return tools.map(tool => ({
38
+ id: tool.arguments[seriesKey],
39
+ name: getName(tool.arguments[seriesKey]),
40
+ type: 'NUMBER'
41
+ }));
42
+ }
29
43
  }
30
- function toRecords(tools) {
44
+ function toRecords(type, seriesKey, tools) {
31
45
  const recordMap = new Map();
32
46
  tools.forEach(tool => {
33
- const {
34
- taskId
35
- } = tool.arguments;
47
+ const id = isAgentId(seriesKey) ? `${tool.arguments.agentId} - ${tool.arguments.taskId}` : tool.arguments[seriesKey];
36
48
  const results = tool?.result?.result || [];
37
49
  results.forEach(result => {
38
50
  const {
@@ -42,7 +54,7 @@ function toRecords(tools) {
42
54
  time: time,
43
55
  metric: {}
44
56
  });
45
- recordMap.get(time).metric[taskId] = result.metric.output;
57
+ recordMap.get(time).metric[id] = result.metric[type];
46
58
  });
47
59
  });
48
60
  return Array.from(recordMap.values()).sort((a, b) => a.time - b.time);
@@ -78,6 +90,9 @@ function fillRecords(tools, records) {
78
90
  }
79
91
  return result;
80
92
  }
93
+ function isAgentId(seriesKey) {
94
+ return seriesKey === 'agentId';
95
+ }
81
96
  function isDaily(tools) {
82
97
  const {
83
98
  from,
@@ -0,0 +1,75 @@
1
+ import React, { useMemo, useState } from "react";
2
+ import { MenuItem, Select } from "@nethru/ui";
3
+ import * as ChartColors from "../../../charts/ChartColors";
4
+ import StackedAreaChartContent from "./StackedAreaChartContent";
5
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
6
+ const metrics = {
7
+ collect: 'output',
8
+ convert: [{
9
+ label: '처리',
10
+ key: 'output'
11
+ }, {
12
+ label: '필터됨',
13
+ key: 'filter'
14
+ }, {
15
+ label: '에러',
16
+ key: 'error'
17
+ }],
18
+ transport: [{
19
+ label: '처리',
20
+ key: 'output'
21
+ }, {
22
+ label: '에러',
23
+ key: 'error'
24
+ }]
25
+ };
26
+ export default function StackedAreaTrendChartWithSelectContent({
27
+ tools,
28
+ selectKey,
29
+ ...props
30
+ }) {
31
+ const [metric, setMetric] = useState('output');
32
+ const colors = useMemo(() => {
33
+ return tools.map((_, index) => ChartColors.colors[(index + 1) % ChartColors.colors.length]);
34
+ }, [tools]);
35
+ return /*#__PURE__*/_jsxs(_Fragment, {
36
+ children: [selectKey !== undefined && Array.isArray(metrics[selectKey]) && /*#__PURE__*/_jsx(MetricSelect, {
37
+ value: metric,
38
+ onChange: e => setMetric(e.target.value),
39
+ type: selectKey
40
+ }), /*#__PURE__*/_jsx("div", {
41
+ children: /*#__PURE__*/_jsx(StackedAreaChartContent, {
42
+ seriesKey: "agentId",
43
+ type: metric,
44
+ tools: tools,
45
+ tooltipOutSide: selectKey !== 'collect',
46
+ yAxisLabelEnabled: false,
47
+ colors: colors,
48
+ legendAlign: "right",
49
+ height: 220,
50
+ ...props
51
+ })
52
+ })]
53
+ });
54
+ }
55
+ function MetricSelect({
56
+ value,
57
+ onChange,
58
+ type
59
+ }) {
60
+ return /*#__PURE__*/_jsx(Select, {
61
+ value: value,
62
+ onChange: onChange,
63
+ sx: {
64
+ position: 'absolute',
65
+ top: '34px',
66
+ left: '6px',
67
+ zIndex: 1,
68
+ width: '92px'
69
+ },
70
+ children: metrics[type].map(metric => /*#__PURE__*/_jsx(MenuItem, {
71
+ value: metric.key,
72
+ children: metric.label
73
+ }, metric.key))
74
+ });
75
+ }
@@ -101,18 +101,20 @@ export function ChatProvider({
101
101
  });
102
102
  return await response.json();
103
103
  }
104
- const sendMessage = async () => {
105
- const message = inputValue.trim();
104
+ const sendMessage = async (messageToSend = null) => {
105
+ const message = messageToSend ?? inputValue.trim();
106
106
  if (!message) return;
107
- const userMessage = {
108
- role: 'user',
109
- content: [{
110
- type: 'text',
111
- value: message
112
- }]
113
- };
114
- setMessages(prev => [...prev, userMessage]);
115
- setInputValue('');
107
+ if (!messageToSend) {
108
+ const userMessage = {
109
+ role: 'user',
110
+ content: [{
111
+ type: 'text',
112
+ value: message
113
+ }]
114
+ };
115
+ setMessages(prev => [...prev, userMessage]);
116
+ setInputValue('');
117
+ }
116
118
  setIsLoading(true);
117
119
  try {
118
120
  let data = option === 'ANALYZE' ? await analyzePage(message) : await answer(message);
@@ -140,6 +142,10 @@ export function ChatProvider({
140
142
  setConversationId(null);
141
143
  setInputValue('');
142
144
  };
145
+ const retrySend = async retryMessage => {
146
+ setMessages(prev => prev.at(-1)?.role === 'assistant' ? prev.slice(0, -1) : prev);
147
+ await sendMessage(retryMessage);
148
+ };
143
149
  const value = {
144
150
  messages,
145
151
  inputValue,
@@ -159,6 +165,7 @@ export function ChatProvider({
159
165
  chatContainerRef,
160
166
  pageRef,
161
167
  sendMessage,
168
+ retrySend,
162
169
  clearChat,
163
170
  conversationId
164
171
  };
@@ -9,8 +9,9 @@ export function ToolContextProvider({
9
9
  const tools = useMemo(() => message.content.filter(c => c.type === 'tool'), [message]);
10
10
  const containerConfigMap = useMemo(() => makeContainerConfigs(tools), [tools]);
11
11
  const taskConfigMap = useMemo(() => makeTaskConfigs(tools), [tools]);
12
- const getName = useCallback((containerId, taskId) => {
13
- return containerConfigMap.get(containerId) || taskConfigMap.get(taskId);
12
+ const agentConfigMap = useMemo(() => makeAgentConfigs(tools), [tools]);
13
+ const getName = useCallback(id => {
14
+ return containerConfigMap.get(id) || taskConfigMap.get(id) || agentConfigMap.get(id);
14
15
  }, [containerConfigMap, taskConfigMap]);
15
16
  return /*#__PURE__*/_jsx(ToolContext.Provider, {
16
17
  value: {
@@ -43,4 +44,13 @@ function makeTaskConfigs(tools) {
43
44
  });
44
45
  });
45
46
  return map;
47
+ }
48
+ function makeAgentConfigs(tools) {
49
+ const map = new Map();
50
+ tools.filter(t => t.name === 'search-agent-by-keyword').forEach(tool => {
51
+ tool.result?.result?.forEach(item => {
52
+ map.set(item.agentId, item.agentName);
53
+ });
54
+ });
55
+ return map;
46
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nethru/kit",
3
- "version": "1.1.17",
3
+ "version": "1.1.19",
4
4
  "description": "A React component library by Nethru",
5
5
  "main": "dist/index.js",
6
6
  "homepage": ".",