@ray-js/t-agent-ui-ray 0.2.8-beta.2 → 0.2.8-beta.3

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.
@@ -3,8 +3,8 @@ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutPr
3
3
  const _excluded = ["src", "bizType"];
4
4
  import "core-js/modules/web.dom-collections.iterator.js";
5
5
  import React, { useMemo, useRef, useState } from 'react';
6
- import { Image, View } from '@ray-js/ray';
7
- import { getUrlByCloudKey, isLinkExpired, parseCloudKey, isFullLink } from '../utils/file';
6
+ import { Image } from '@ray-js/ray';
7
+ import { getUrlByCloudKey, isLinkExpired, parseCloudKey } from '../utils/file';
8
8
  import logger from '../logger';
9
9
  const PrivateImage = /*#__PURE__*/React.forwardRef((props, ref) => {
10
10
  const {
@@ -73,13 +73,10 @@ const PrivateImage = /*#__PURE__*/React.forwardRef((props, ref) => {
73
73
  // }
74
74
  // }, [expired, url, bizType]);
75
75
 
76
- if (loading || !url || !isFullLink(url)) {
77
- return /*#__PURE__*/React.createElement(View, {
78
- key: url,
79
- className: rest.className,
80
- style: rest.style
81
- });
82
- }
76
+ // if (loading || !url || !isFullLink(url)) {
77
+ // return <View key={url} className={rest.className} style={rest.style} />;
78
+ // }
79
+
83
80
  return /*#__PURE__*/React.createElement(Image, _extends({
84
81
  ref: ref,
85
82
  key: url,
@@ -107,7 +104,7 @@ const PrivateImage = /*#__PURE__*/React.forwardRef((props, ref) => {
107
104
  }
108
105
  (_props$onError = props.onError) === null || _props$onError === void 0 || _props$onError.call(props, event);
109
106
  },
110
- src: url
107
+ src: src
111
108
  }, rest));
112
109
  });
113
110
  export default PrivateImage;
@@ -2,5 +2,19 @@ import './index.less';
2
2
  import React from 'react';
3
3
  import { BubbleTileData } from '@ray-js/t-agent';
4
4
  import { TileProps } from '../../types';
5
- declare const _default: React.MemoExoticComponent<(props: TileProps<BubbleTileData>) => React.JSX.Element>;
5
+ /** Unified props passed to every overridable slot component of BubbleTile. */
6
+ type BubbleTileSlotProps = TileProps<BubbleTileData>;
7
+ export interface BubbleTileProps extends TileProps<BubbleTileData> {
8
+ /** Rendered at the top of the bubble content, before the children. */
9
+ Header?: React.ComponentType<BubbleTileSlotProps>;
10
+ /** Rendered at the bottom of the bubble content, after the children. */
11
+ Footer?: React.ComponentType<BubbleTileSlotProps>;
12
+ /** Overrides the default error / warning side icon. */
13
+ ErrorNotice?: React.ComponentType<BubbleTileSlotProps>;
14
+ /** Overrides the default loading indicator. */
15
+ LoadingIndicator?: React.ComponentType<BubbleTileSlotProps>;
16
+ /** Overrides the standalone error-alert bubble (empty assistant error message). */
17
+ ErrorBubble?: React.ComponentType<BubbleTileSlotProps>;
18
+ }
19
+ declare const _default: React.MemoExoticComponent<(props: BubbleTileProps) => React.JSX.Element>;
6
20
  export default _default;
@@ -1,26 +1,31 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import "core-js/modules/esnext.iterator.constructor.js";
3
- import "core-js/modules/esnext.iterator.find.js";
4
3
  import "core-js/modules/esnext.iterator.map.js";
5
- import "core-js/modules/esnext.iterator.some.js";
6
4
  import './index.less';
7
5
  import { View } from '@ray-js/components';
8
- import React, { memo, useCallback, useMemo } from 'react';
6
+ import React, { memo, useMemo } from 'react';
9
7
  import { BubbleTileStatus, ChatMessageStatus } from '@ray-js/t-agent';
10
8
  import TileRender from '../../TileRender';
11
9
  import { useLongPress, useRenderOptions, useTranslate } from '../../hooks';
12
- import RollBack from '../WorkflowTile/RollBack';
10
+ import { getMessageContent as _getMessageContent } from '../../utils';
11
+ import { useStableCallback } from '../../hooks/useStableCallback';
12
+
13
+ /** Unified props passed to every overridable slot component of BubbleTile. */
14
+
13
15
  const BubbleTile = props => {
14
- var _workflowTile$data;
15
16
  const {
16
- renderLongPressAs,
17
- formatErrorMessageAs
17
+ renderLongPressAs
18
18
  } = useRenderOptions();
19
19
  const {
20
20
  message,
21
21
  tile,
22
22
  isLatestMessage,
23
- side
23
+ side,
24
+ Header,
25
+ Footer,
26
+ ErrorNotice = DefaultErrorNotice,
27
+ LoadingIndicator = DefaultLoadingIndicator,
28
+ ErrorBubble = DefaultErrorBubble
24
29
  } = props;
25
30
  const {
26
31
  status,
@@ -33,24 +38,7 @@ const BubbleTile = props => {
33
38
  const bubbleStatus = data.status || BubbleTileStatus.NORMAL;
34
39
  const t = useTranslate();
35
40
  const loading = status === ChatMessageStatus.START || status === ChatMessageStatus.UPDATING;
36
-
37
- // 获取消息内容的函数
38
- const getMessageContent = useCallback(() => {
39
- let messageContent = '';
40
- if (tile.children && tile.children.length > 0) {
41
- // 查找文本类型的tile
42
- const textTile = tile.children.find(child => child.type === 'text');
43
- if (textTile && textTile.data && typeof textTile.data === 'object' && 'text' in textTile.data) {
44
- messageContent = textTile.data.text;
45
- }
46
- }
47
-
48
- // 如果是文本类型的tile,直接获取文本内容
49
- if (tile.type === 'text' && tile.data && typeof tile.data === 'object' && 'text' in tile.data) {
50
- messageContent = tile.data.text;
51
- }
52
- return messageContent;
53
- }, [tile]);
41
+ const getMessageContent = useStableCallback(() => _getMessageContent(message));
54
42
  const longPressRes = useLongPress({
55
43
  message,
56
44
  actions: role === 'assistant' ? ['copy', 'multiSelect', 'delete', 'like', 'unlike'] : ['copy', 'multiSelect', 'delete'],
@@ -58,6 +46,7 @@ const BubbleTile = props => {
58
46
  disabled: loading
59
47
  });
60
48
  const longPressBlock = renderLongPressAs(longPressRes);
49
+ const slotProps = props;
61
50
  const isErrorBubble = useMemo(() => {
62
51
  let empty = true;
63
52
  for (let i = 0; i < children.length; i++) {
@@ -76,38 +65,13 @@ const BubbleTile = props => {
76
65
  }
77
66
  return empty && role === 'assistant' && bubbleStatus === BubbleTileStatus.ERROR && status === ChatMessageStatus.FINISH;
78
67
  }, [status, role, bubbleStatus, children]);
79
- if (isErrorBubble) {
80
- return /*#__PURE__*/React.createElement(View, _extends({
81
- className: "t-agent-bubble-tile t-agent-bubble-tile-error-alert",
82
- "data-testid": "t-agent-bubble-tile"
83
- }, longPressRes.longPressProps), /*#__PURE__*/React.createElement(View, {
84
- className: "t-agent-bubble-tile-error",
85
- "data-testid": "t-agent-bubble-tile-error"
86
- }), /*#__PURE__*/React.createElement(View, {
87
- className: "t-agent-bubble-tile-error-alert-text"
88
- }, formatErrorMessageAs(data.info, data.code) || t('t-agent.error.unknown-error')), longPressBlock);
89
- }
90
- const showInfo = () => {
91
- if (data.info) {
92
- ty.showToast({
93
- title: formatErrorMessageAs(data.info, data.code),
94
- icon: 'none'
95
- });
96
- }
97
- };
98
68
  const showAbortedMessage = bubbleStatus === BubbleTileStatus.ABORTED;
99
- const showRollBack = side === 'start' && children.some(child => child.type === 'workflow');
100
- const workflowTile = children.find(child => child.type === 'workflow');
101
- const workflowNode = workflowTile === null || workflowTile === void 0 || (_workflowTile$data = workflowTile.data) === null || _workflowTile$data === void 0 ? void 0 : _workflowTile$data.nodeId;
102
69
  return /*#__PURE__*/React.createElement(View, _extends({
103
- className: "t-agent-bubble-tile t-agent-bubble-tile-".concat(side),
70
+ className: "t-agent-bubble-tile t-agent-bubble-tile-".concat(side, " ").concat(isErrorBubble ? 't-agent-bubble-tile-error-alert' : ''),
104
71
  "data-testid": "t-agent-bubble-tile"
105
- }, longPressRes.longPressProps), side === 'end' && /*#__PURE__*/React.createElement(ErrorNotice, {
106
- bubbleStatus: bubbleStatus,
107
- showInfo: showInfo
108
- }), /*#__PURE__*/React.createElement(View, {
72
+ }, longPressRes.longPressProps), isErrorBubble ? /*#__PURE__*/React.createElement(ErrorBubble, slotProps) : /*#__PURE__*/React.createElement(React.Fragment, null, side === 'end' && /*#__PURE__*/React.createElement(ErrorNotice, slotProps), /*#__PURE__*/React.createElement(View, {
109
73
  className: "t-agent-bubble-tile-bubble ".concat(loading ? 't-agent-bubble-tile-bubble-loading' : '')
110
- }, (() => {
74
+ }, Header && /*#__PURE__*/React.createElement(Header, slotProps), (() => {
111
75
  return children.map(t => /*#__PURE__*/React.createElement(TileRender, {
112
76
  side: side,
113
77
  tile: t,
@@ -116,22 +80,47 @@ const BubbleTile = props => {
116
80
  isLatestMessage: isLatestMessage,
117
81
  notifyHeightChanged: props.notifyHeightChanged
118
82
  }));
119
- })(), /*#__PURE__*/React.createElement(LoadingIndicator, {
120
- status: status
121
- }), showAbortedMessage && /*#__PURE__*/React.createElement(View, {
83
+ })(), /*#__PURE__*/React.createElement(LoadingIndicator, slotProps), showAbortedMessage && /*#__PURE__*/React.createElement(View, {
122
84
  className: "t-agent-bubble-tile-aborted"
123
- }, t('t-agent.message.bubble.aborted'))), side === 'start' && /*#__PURE__*/React.createElement(ErrorNotice, {
124
- bubbleStatus: bubbleStatus,
125
- showInfo: showInfo
126
- }), longPressBlock, showRollBack && !isLatestMessage && workflowNode && /*#__PURE__*/React.createElement(RollBack, {
127
- nodeId: workflowNode
128
- }));
85
+ }, t('t-agent.message.bubble.aborted')), Footer && /*#__PURE__*/React.createElement(Footer, slotProps)), side === 'start' && /*#__PURE__*/React.createElement(ErrorNotice, slotProps)), longPressBlock);
129
86
  };
130
- const ErrorNotice = /*#__PURE__*/memo(_ref => {
87
+ const DefaultErrorBubble = /*#__PURE__*/memo(_ref => {
131
88
  let {
132
- bubbleStatus,
133
- showInfo
89
+ tile
134
90
  } = _ref;
91
+ const {
92
+ formatErrorMessageAs
93
+ } = useRenderOptions();
94
+ const t = useTranslate();
95
+ const {
96
+ data
97
+ } = tile;
98
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
99
+ className: "t-agent-bubble-tile-error",
100
+ "data-testid": "t-agent-bubble-tile-error"
101
+ }), /*#__PURE__*/React.createElement(View, {
102
+ className: "t-agent-bubble-tile-error-alert-text"
103
+ }, formatErrorMessageAs(data.info, data.code) || t('t-agent.error.unknown-error')));
104
+ });
105
+ const DefaultErrorNotice = /*#__PURE__*/memo(_ref2 => {
106
+ let {
107
+ tile
108
+ } = _ref2;
109
+ const {
110
+ formatErrorMessageAs
111
+ } = useRenderOptions();
112
+ const {
113
+ data
114
+ } = tile;
115
+ const bubbleStatus = data.status || BubbleTileStatus.NORMAL;
116
+ const showInfo = () => {
117
+ if (data.info) {
118
+ ty.showToast({
119
+ title: formatErrorMessageAs(data.info, data.code),
120
+ icon: 'none'
121
+ });
122
+ }
123
+ };
135
124
  if (bubbleStatus === BubbleTileStatus.ERROR) {
136
125
  return /*#__PURE__*/React.createElement(View, {
137
126
  onClick: showInfo,
@@ -148,10 +137,13 @@ const ErrorNotice = /*#__PURE__*/memo(_ref => {
148
137
  }
149
138
  return null;
150
139
  });
151
- const LoadingIndicator = /*#__PURE__*/memo(_ref2 => {
140
+ const DefaultLoadingIndicator = /*#__PURE__*/memo(_ref3 => {
152
141
  let {
142
+ message
143
+ } = _ref3;
144
+ const {
153
145
  status
154
- } = _ref2;
146
+ } = message;
155
147
  if (status === ChatMessageStatus.START) {
156
148
  return /*#__PURE__*/React.createElement(View, {
157
149
  className: "t-agent-bubble-tile-bubble-loader"
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="14.666666984558105" height="11.259817123413086" viewBox="0 0 14.666666984558105 11.259817123413086"><path d="M3.7352133,4.2966166L6,2.4435894L6,8.8162832L3.7352133,6.9632831L1.3333334,6.9632831L1.3333334,4.2966166L3.7352133,4.2966166ZM0.66666669,8.2966156L3.2592599,8.2966156L6.7889338,11.184483C6.8484669,11.233217,6.9230666,11.259817,7,11.259817C7.1840668,11.259817,7.3333335,11.110617,7.3333335,10.926483L7.3333335,0.33334273C7.3333335,0.256396,7.3067336,0.18181595,7.2580004,0.12226264C7.1414003,-0.020217419,6.9314003,-0.041217327,6.7889338,0.075356007L3.2592599,2.9632626L0.66666669,2.9632626C0.29848003,2.9632626,0,3.2617359,0,3.6299293L0,7.6299496C0,7.9981494,0.29848003,8.2966156,0.66666669,8.2966156ZM14.666667,5.6298828C14.666667,7.8245497,13.7026,9.7940826,12.1748,11.138016L11.229667,10.192817C12.5172,9.09235,13.333334,7.4564166,13.333334,5.6298828C13.333334,3.8033233,12.5172,2.1674094,11.229667,1.0669293L12.1748,0.12174273C13.7026,1.4656695,14.666667,3.4351826,14.666667,5.6298828ZM11.333334,5.6298828C11.333334,4.3554163,10.737334,3.2202029,9.8088665,2.4877026L8.8561335,3.440443C9.547533,3.9222496,10,4.7232165,10,5.6298828C10,6.5365496,9.547533,7.3374834,8.8561335,7.8192825L9.8088665,8.7720165C10.737334,8.0395498,11.333334,6.904283,11.333334,5.6298828Z" fill="#427FF7" fill-opacity="1" style="mix-blend-mode:passthrough"/></svg>
@@ -0,0 +1,24 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
2
+ <g fill="#427ff7">
3
+ <rect x="2.4" width="2.4" rx="1.2" y="9" height="6">
4
+ <animate attributeName="height" values="6;18;6" dur="0.9s" begin="0s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
5
+ <animate attributeName="y" values="9;3;9" dur="0.9s" begin="0s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
6
+ </rect>
7
+ <rect x="6.6" width="2.4" rx="1.2" y="6" height="12">
8
+ <animate attributeName="height" values="6;18;6" dur="0.9s" begin="-0.3s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
9
+ <animate attributeName="y" values="9;3;9" dur="0.9s" begin="-0.3s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
10
+ </rect>
11
+ <rect x="10.8" width="2.4" rx="1.2" y="3" height="18">
12
+ <animate attributeName="height" values="6;18;6" dur="0.9s" begin="-0.6s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
13
+ <animate attributeName="y" values="9;3;9" dur="0.9s" begin="-0.6s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
14
+ </rect>
15
+ <rect x="15" width="2.4" rx="1.2" y="6" height="12">
16
+ <animate attributeName="height" values="6;18;6" dur="0.9s" begin="-0.15s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
17
+ <animate attributeName="y" values="9;3;9" dur="0.9s" begin="-0.15s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
18
+ </rect>
19
+ <rect x="19.2" width="2.4" rx="1.2" y="9" height="6">
20
+ <animate attributeName="height" values="6;18;6" dur="0.9s" begin="-0.45s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
21
+ <animate attributeName="y" values="9;3;9" dur="0.9s" begin="-0.45s" repeatCount="indefinite" calcMode="spline" keyTimes="0;0.5;1" keySplines="0.4 0 0.6 1;0.4 0 0.6 1" />
22
+ </rect>
23
+ </g>
24
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="16" height="16" viewBox="0 0 16 16"><defs><clipPath id="master_svg0_1631_18176"><rect x="0" y="0" width="16" height="16" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_1631_18176)"><path d="M4.6665335,4.000002576464844L4.6665335,2.0000025664648438C4.6665335,1.6318159064648436,4.9650133,1.3333358764648438,5.3332002,1.3333358764648438L13.3332,1.3333358764648438C13.7014,1.3333358764648438,13.999866,1.6318159064648436,13.999866,2.0000025664648438L13.999866,11.333335876464844C13.999866,11.701535876464844,13.7014,12.000002876464844,13.3332,12.000002876464844L11.3332005,12.000002876464844L11.3332005,13.999402876464844C11.3332005,14.367936876464844,11.033267,14.666669876464844,10.6620007,14.666669876464844L2.6711067,14.666669876464844C2.3003932799999998,14.666669876464844,2,14.370269876464844,2,13.999402876464844L2.0017333031,4.667249476464844C2.0018000603,4.298742776464843,2.30176005,4.000002576464844,2.67294663,4.000002576464844L4.6665335,4.000002576464844ZM3.3349466000000003,5.333335876464844L3.3334599000000003,13.333335876464844L9.9998665,13.333335876464844L9.9998665,5.333335876464844L3.3349466000000003,5.333335876464844ZM5.9998664999999995,4.000002576464844L11.3332005,4.000002576464844L11.3332005,10.666669876464844L12.666533,10.666669876464844L12.666533,2.6666692764648436L5.9998664999999995,2.6666692764648436L5.9998664999999995,4.000002576464844Z" fill="#427FF7" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></svg>
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import './index.less';
3
+ import { TileProps } from '../../types';
4
+ export interface BubbleToolTileData {
5
+ /** 播放所需的音频参数,由 aistream 插件下发时写入 */
6
+ audio?: Record<string, any>;
7
+ [key: string]: any;
8
+ }
9
+ declare const _default: React.MemoExoticComponent<(props: TileProps<BubbleToolTileData>) => React.JSX.Element | null>;
10
+ export default _default;
@@ -0,0 +1,63 @@
1
+ import "core-js/modules/web.dom-collections.iterator.js";
2
+ import React, { useEffect } from 'react';
3
+ import { View } from '@ray-js/components';
4
+ import './index.less';
5
+ import { useAgentSessionValue, useTranslate } from '../../hooks';
6
+ import { getMessageContent } from '../../utils';
7
+ const BubbleToolTile = props => {
8
+ const {
9
+ message,
10
+ isLatestMessage,
11
+ notifyHeightChanged
12
+ } = props;
13
+ // playing 不是 tile 的本地状态,而是从 session 的全局播放状态派生:
14
+ // 真正的播放/停止由 withBuildIn 处理,并把 “是否正在播放 / 正在播放的消息 id”
15
+ // 写入 session,UI 通过 sessionChange 事件感知变化。
16
+ const [audioPlaying] = useAgentSessionValue('AIStream.audioPlaying');
17
+ const [playingMessageId] = useAgentSessionValue('AIStream.playingMessageId');
18
+ const playing = !!audioPlaying && playingMessageId === message.id;
19
+
20
+ // UI 只负责发指令
21
+
22
+ const show = message.role === 'assistant' && isLatestMessage;
23
+ const t = useTranslate();
24
+ useEffect(() => {
25
+ if (!show) {
26
+ notifyHeightChanged();
27
+ }
28
+ }, [show]);
29
+ if (!show) {
30
+ return null;
31
+ }
32
+ return /*#__PURE__*/React.createElement(View, {
33
+ className: "t-agent-bubble-tool-tile"
34
+ }, /*#__PURE__*/React.createElement(View, {
35
+ className: "t-agent-bubble-tool-tile-divider"
36
+ }), /*#__PURE__*/React.createElement(View, {
37
+ className: "t-agent-bubble-tool-tile-actions"
38
+ }, /*#__PURE__*/React.createElement(View, {
39
+ className: "t-agent-bubble-tool-tile-button ".concat(playing ? 't-agent-bubble-tool-tile-play-active' : 't-agent-bubble-tool-tile-play'),
40
+ "data-testid": "t-agent-bubble-tool-tile-play",
41
+ onClick: () => {
42
+ props.emitTileEvent({
43
+ action: 'toggle'
44
+ });
45
+ }
46
+ }), /*#__PURE__*/React.createElement(View, {
47
+ className: "t-agent-bubble-tool-tile-button t-agent-bubble-tool-tile-copy",
48
+ "data-testid": "t-agent-bubble-tool-tile-copy",
49
+ onClick: () => {
50
+ const text = getMessageContent(message);
51
+ ty.setClipboardData({
52
+ data: text,
53
+ success() {
54
+ ty.showToast({
55
+ title: t('t-agent.message.copy.success'),
56
+ icon: 'none'
57
+ });
58
+ }
59
+ });
60
+ }
61
+ })));
62
+ };
63
+ export default /*#__PURE__*/React.memo(BubbleToolTile);
@@ -0,0 +1,46 @@
1
+ .t-agent-bubble-tool-tile {
2
+ }
3
+
4
+ .t-agent-bubble-tool-tile-divider {
5
+ flex: 1;
6
+ height: 1px;
7
+ background-color: var(--app-B3-N1);
8
+ opacity: 0.12;
9
+ margin: 16rpx 0;
10
+ }
11
+
12
+ .t-agent-bubble-tool-tile-actions {
13
+ display: flex;
14
+ }
15
+
16
+ .t-agent-bubble-tool-tile-button {
17
+ flex: 0 0 auto;
18
+ width: 48rpx;
19
+ height: 48rpx;
20
+ border-radius: 8rpx;
21
+ background-color: var(--app-B1);
22
+ background-repeat: no-repeat;
23
+ background-position: center center;
24
+ background-size: 28rpx 28rpx;
25
+ margin-right: 16rpx;
26
+
27
+ :first-child {
28
+ margin-right: 0;
29
+ }
30
+ }
31
+
32
+ .t-agent-bubble-tool-tile-play {
33
+ background-image: url("./audio-play.svg");
34
+ }
35
+
36
+ .t-agent-bubble-tool-tile-play-active {
37
+ background-image: url("./audio-playing.svg");
38
+ }
39
+
40
+ .t-agent-bubble-tool-tile-copy {
41
+ background-image: url("./copy.svg");
42
+ }
43
+
44
+ .t-agent-bubble-tool-tile-play-active {
45
+ opacity: 0.6;
46
+ }
@@ -1,8 +1,15 @@
1
1
  import "core-js/modules/web.dom-collections.iterator.js";
2
2
  import { View } from '@ray-js/components';
3
3
  import React, { useEffect, useMemo, useState } from 'react';
4
- import dayjs from 'dayjs';
5
4
  import './index.less';
5
+ function formatDate(timestamp) {
6
+ const d = new Date(timestamp);
7
+ return [d.getFullYear(), String(d.getMonth() + 1).padStart(2, '0'), String(d.getDate()).padStart(2, '0')].join('-');
8
+ }
9
+ function formatTime(timestamp) {
10
+ const d = new Date(timestamp);
11
+ return [String(d.getHours()).padStart(2, '0'), String(d.getMinutes()).padStart(2, '0')].join(':');
12
+ }
6
13
  export default function TimeTile(props) {
7
14
  const {
8
15
  tile
@@ -10,25 +17,19 @@ export default function TimeTile(props) {
10
17
  const {
11
18
  timestamp
12
19
  } = tile.data;
13
- const [date, setDate] = useState(() => {
14
- return dayjs(timestamp).format('YYYY-MM-DD');
15
- });
20
+ const [today, setToday] = useState(() => formatDate(Date.now()));
16
21
  useEffect(() => {
17
- // 在当天结束时更新一下
22
+ const now = new Date();
23
+ const nextDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
18
24
  const timer = setTimeout(() => {
19
- setDate(dayjs(timestamp).format('YYYY-MM-DD'));
20
- }, dayjs(timestamp).endOf('day').diff(Date.now()));
21
- return () => {
22
- clearTimeout(timer);
23
- };
25
+ setToday(formatDate(Date.now()));
26
+ }, nextDay.getTime() - now.getTime());
27
+ return () => clearTimeout(timer);
24
28
  }, []);
25
29
  const time = useMemo(() => {
26
- // 当天的时间只显示时间,其他显示日期和时间
27
- if (date === dayjs(Date.now()).format('YYYY-MM-DD')) {
28
- return dayjs(timestamp).format('HH:mm');
29
- }
30
- return dayjs(timestamp).format('YYYY-MM-DD HH:mm');
31
- }, [timestamp, date]);
30
+ const tsDate = formatDate(timestamp);
31
+ return tsDate === today ? formatTime(timestamp) : "".concat(tsDate, " ").concat(formatTime(timestamp));
32
+ }, [timestamp, today]);
32
33
  return /*#__PURE__*/React.createElement(View, {
33
34
  className: "t-agent-time-tile"
34
35
  }, time);
package/dist/tiles/map.js CHANGED
@@ -7,12 +7,12 @@ import VideoTile from './VideoTile';
7
7
  import ButtonGroupTile from './ButtonsTile';
8
8
  import RecommendationsTile from './RecommendationsTile';
9
9
  import CardTile from './CardTile';
10
- import WorkflowTile from './WorkflowTile';
11
10
  import DocumentsTile from './DocumentsTile';
12
11
  import OperateCardTile from './OperateCardTile';
13
12
  import ExecuteCardTile from './ExecuteCardTile';
14
13
  import DividerTile from './DividerTile';
15
14
  import FileTile from './FileTile';
15
+ import BubbleToolTile from './BubbleToolTile';
16
16
  export const tileMap = {
17
17
  bubble: BubbleTile,
18
18
  image: ImageTile,
@@ -23,10 +23,10 @@ export const tileMap = {
23
23
  buttons: ButtonGroupTile,
24
24
  recommendations: RecommendationsTile,
25
25
  card: CardTile,
26
- workflow: WorkflowTile,
27
26
  documents: DocumentsTile,
28
27
  operateCard: OperateCardTile,
29
28
  executeCard: ExecuteCardTile,
30
29
  divider: DividerTile,
31
- file: FileTile
30
+ file: FileTile,
31
+ bubbleTool: BubbleToolTile
32
32
  };
@@ -0,0 +1,11 @@
1
+ import { ChatMessageObject } from '@ray-js/t-agent';
2
+ /**
3
+ * 从 message 中提取文本内容。
4
+ *
5
+ * 遍历 message 的所有 tile,取第一个能解析出文本的 tile:
6
+ * - 若 tile 自身为 `text` 类型,返回其文本;
7
+ * - 否则查找其 children 中的第一个 `text` 类型 tile 并返回文本。
8
+ *
9
+ * 可在任意 tile 中复用,例如长按复制消息内容。
10
+ */
11
+ export declare function getMessageContent(message?: ChatMessageObject): string;
@@ -0,0 +1,49 @@
1
+ import "core-js/modules/esnext.iterator.constructor.js";
2
+ import "core-js/modules/esnext.iterator.find.js";
3
+ const getTileText = data => {
4
+ if (data && typeof data === 'object' && 'text' in data) {
5
+ return data.text || '';
6
+ }
7
+ return '';
8
+ };
9
+ const getTextFromTile = tile => {
10
+ if (!tile) {
11
+ return '';
12
+ }
13
+
14
+ // 如果是文本类型的 tile,直接获取文本内容
15
+ if (tile.type === 'text') {
16
+ return getTileText(tile.data);
17
+ }
18
+
19
+ // 查找子 tile 中的文本类型 tile
20
+ if (tile.children && tile.children.length > 0) {
21
+ const textTile = tile.children.find(child => child.type === 'text');
22
+ if (textTile) {
23
+ return getTileText(textTile.data);
24
+ }
25
+ }
26
+ return '';
27
+ };
28
+
29
+ /**
30
+ * 从 message 中提取文本内容。
31
+ *
32
+ * 遍历 message 的所有 tile,取第一个能解析出文本的 tile:
33
+ * - 若 tile 自身为 `text` 类型,返回其文本;
34
+ * - 否则查找其 children 中的第一个 `text` 类型 tile 并返回文本。
35
+ *
36
+ * 可在任意 tile 中复用,例如长按复制消息内容。
37
+ */
38
+ export function getMessageContent(message) {
39
+ if (!message || !message.tiles || message.tiles.length === 0) {
40
+ return '';
41
+ }
42
+ for (let i = 0; i < message.tiles.length; i++) {
43
+ const content = getTextFromTile(message.tiles[i]);
44
+ if (content) {
45
+ return content;
46
+ }
47
+ }
48
+ return '';
49
+ }
@@ -1,3 +1,4 @@
1
1
  export declare function routeScene(sceneId: string): void;
2
2
  export declare const systemInfo: any;
3
3
  export * from './formatMessage';
4
+ export * from './getMessageContent';
@@ -12,4 +12,5 @@ export function routeScene(sceneId) {
12
12
  });
13
13
  }
14
14
  export const systemInfo = ty.getSystemInfoSync();
15
- export * from './formatMessage';
15
+ export * from './formatMessage';
16
+ export * from './getMessageContent';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent-ui-ray",
3
- "version": "0.2.8-beta.2",
3
+ "version": "0.2.8-beta.3",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -27,7 +27,6 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "clsx": "^1.2.1",
30
- "dayjs": "^1.10.4",
31
30
  "echarts": "^5.5.0",
32
31
  "markdown-it": "^14.1.0",
33
32
  "markdown-it-emoji": "^3.0.0",
@@ -42,5 +41,5 @@
42
41
  "@types/echarts": "^4.9.22",
43
42
  "@types/markdown-it": "^14.1.1"
44
43
  },
45
- "gitHead": "450ca8d41536094b3bea57198fd7724ba6812438"
44
+ "gitHead": "938bc0c7da7d23dbbad8c3c14c97e5f4007f06f7"
46
45
  }
@@ -1,5 +0,0 @@
1
- import './index.less';
2
- import React from 'react';
3
- export default function RollBack(props: {
4
- nodeId: string;
5
- }): React.JSX.Element;
@@ -1,27 +0,0 @@
1
- import './index.less';
2
- import { Image, View } from '@ray-js/ray';
3
- import React from 'react';
4
- import rollback from './workflow-rollback.png';
5
- import { useTileProps } from '../../../hooks';
6
- export default function RollBack(props) {
7
- const {
8
- nodeId
9
- } = props;
10
- const {
11
- emitTileEvent
12
- } = useTileProps();
13
- return /*#__PURE__*/React.createElement(View, {
14
- className: "t-agent-workflow-rollback-tile",
15
- onClick: async () => {
16
- emitTileEvent({
17
- type: 'rollback',
18
- nodeId
19
- });
20
- }
21
- }, /*#__PURE__*/React.createElement(Image, {
22
- src: rollback,
23
- className: "t-agent-workflow-rollback-tile-image"
24
- }), /*#__PURE__*/React.createElement(View, {
25
- className: "t-agent-workflow-rollback-tile-text"
26
- }, "\u91CD\u9009"));
27
- }
@@ -1,20 +0,0 @@
1
- .t-agent-workflow-rollback-tile {
2
- color: var(--app-B3-N1);
3
- background-color: var(--app-B3);
4
- border-radius: 9999px;
5
- height: 36px;
6
- margin-top: 8px;
7
- width: fit-content;
8
- line-height: 36px;
9
- padding: 0 12px;
10
- display: flex;
11
- align-items: center;
12
- justify-content: center;
13
- .t-agent-workflow-rollback-tile-image {
14
- width: 20px;
15
- height: 20px;
16
- margin-right: 6px;
17
- }
18
- .t-agent-workflow-rollback-tile-text {
19
- }
20
- }