@myun/gimi-chat 0.9.65 → 0.9.67
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.
- package/dist/apis/useApi.d.ts +6 -0
- package/dist/apis/useApi.js +45 -1
- package/dist/components/ai-chat-dialogue/index copy.js +1 -1
- package/dist/components/ai-chat-dialogue/index.js +4 -2
- package/dist/components/answer-item/component/artifacts/index.d.ts +13 -0
- package/dist/components/answer-item/component/artifacts/index.js +52 -0
- package/dist/components/answer-item/component/artifacts/index.module.css +24 -0
- package/dist/components/answer-item/component/tool-list/index.d.ts +7 -0
- package/dist/components/answer-item/component/tool-list/index.js +117 -0
- package/dist/components/answer-item/component/tool-list/index.module.css +97 -0
- package/dist/components/answer-item/index.d.ts +2 -1
- package/dist/components/answer-item/index.js +179 -8
- package/dist/components/answer-item/index.module.css +35 -0
- package/dist/components/ask-card/index.d.ts +1 -1
- package/dist/components/chat-input/extension/index.d.ts +1 -0
- package/dist/components/chat-input/extension/index.js +2 -1
- package/dist/components/chat-input/extension/skill/MentionList.d.ts +32 -0
- package/dist/components/chat-input/extension/skill/MentionList.js +206 -0
- package/dist/components/chat-input/extension/skill/ReferSlot.d.ts +3 -0
- package/dist/components/chat-input/extension/skill/ReferSlot.js +100 -0
- package/dist/components/chat-input/extension/skill/data.d.ts +10 -0
- package/dist/components/chat-input/extension/skill/data.js +49 -0
- package/dist/components/chat-input/extension/skill/index.d.ts +7 -0
- package/dist/components/chat-input/extension/skill/index.js +5 -0
- package/dist/components/chat-input/extension/skill/index.less +117 -0
- package/dist/components/chat-input/extension/skill/suggestion.d.ts +16 -0
- package/dist/components/chat-input/extension/skill/suggestion.js +228 -0
- package/dist/components/chat-input/index.js +145 -24
- package/dist/components/chat-input/index.module.css +6 -0
- package/dist/components/file-card/index.js +2 -1
- package/dist/components/file-card/index.module.css +1 -0
- package/dist/components/knowledge-trace/KnowledgeIconComponent.js +6 -1
- package/dist/components/knowledge-trace/tryWatch.js +2 -2
- package/dist/components/message-list/index.js +15 -3
- package/dist/components/message-list/index.module.css +3 -0
- package/dist/components/message-list/skill-tag/index.d.ts +5 -0
- package/dist/components/message-list/skill-tag/index.js +23 -0
- package/dist/components/message-list/skill-tag/index.module.css +22 -0
- package/dist/components/templates/CommonChat.js +3 -1
- package/dist/hooks/useChatActions.d.ts +2 -1
- package/dist/hooks/useChatActions.js +52 -12
- package/dist/hooks/useChatStream.d.ts +6 -1
- package/dist/hooks/useChatStream.js +97 -5
- package/dist/hooks/useCommonChatAPI.d.ts +1 -1
- package/dist/hooks/useCommonChatAPI.js +212 -58
- package/dist/i18n/locales/en-US.d.ts +7 -0
- package/dist/i18n/locales/en-US.js +8 -1
- package/dist/i18n/locales/zh-CN.d.ts +7 -0
- package/dist/i18n/locales/zh-CN.js +8 -1
- package/dist/interfaces/chatMessage.d.ts +40 -0
- package/dist/umd/index.min.js +1 -1
- package/dist/utils/tools.d.ts +7 -0
- package/dist/utils/tools.js +38 -1
- package/package.json +4 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Node, mergeAttributes } from '@tiptap/core';
|
|
3
|
+
import { ReactNodeViewRenderer, NodeViewWrapper } from '@tiptap/react';
|
|
4
|
+
import { AIChatInput } from '@douyinfe/semi-ui';
|
|
5
|
+
|
|
6
|
+
// referSlot 的渲染组件
|
|
7
|
+
function ReferSlotComponent(props) {
|
|
8
|
+
console.log('props', props);
|
|
9
|
+
var node = props.node,
|
|
10
|
+
deleteNode = props.deleteNode;
|
|
11
|
+
var info = node.attrs.info ? JSON.parse(node.attrs.info) || {} : {};
|
|
12
|
+
var onRemove = function onRemove(e) {
|
|
13
|
+
e.preventDefault();
|
|
14
|
+
e.stopPropagation();
|
|
15
|
+
deleteNode && deleteNode();
|
|
16
|
+
};
|
|
17
|
+
return /*#__PURE__*/React.createElement(NodeViewWrapper, {
|
|
18
|
+
className: "ai-chat-input-refer-slot-wrapper"
|
|
19
|
+
}, /*#__PURE__*/React.createElement("img", {
|
|
20
|
+
className: "ai-chat-input-refer-slot-image",
|
|
21
|
+
src: "https://simg01.gaodunwangxiao.com/uploadfiles/tmp/upload/202608/27/50553_20260827090545.png",
|
|
22
|
+
alt: ""
|
|
23
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
24
|
+
className: "ai-chat-input-refer-slot"
|
|
25
|
+
}, info.toolName || ''));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 创建 ReferSlot 扩展
|
|
29
|
+
var ReferSlot = Node.create({
|
|
30
|
+
name: 'referSlot',
|
|
31
|
+
inline: true,
|
|
32
|
+
group: 'inline',
|
|
33
|
+
atom: true,
|
|
34
|
+
selectable: false,
|
|
35
|
+
addAttributes: function addAttributes() {
|
|
36
|
+
return {
|
|
37
|
+
value: {
|
|
38
|
+
default: '输入内容',
|
|
39
|
+
parseHTML: function parseHTML(element) {
|
|
40
|
+
return element.getAttribute('data-value');
|
|
41
|
+
},
|
|
42
|
+
renderHTML: function renderHTML(attributes) {
|
|
43
|
+
return {
|
|
44
|
+
'data-value': attributes.value
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
info: {
|
|
49
|
+
default: '',
|
|
50
|
+
parseHTML: function parseHTML(element) {
|
|
51
|
+
return element.getAttribute('data-info');
|
|
52
|
+
},
|
|
53
|
+
renderHTML: function renderHTML(attributes) {
|
|
54
|
+
return {
|
|
55
|
+
'data-info': attributes.info
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
type: {
|
|
60
|
+
default: 'text',
|
|
61
|
+
parseHTML: function parseHTML(element) {
|
|
62
|
+
return element.getAttribute('data-type');
|
|
63
|
+
},
|
|
64
|
+
renderHTML: function renderHTML(attributes) {
|
|
65
|
+
return {
|
|
66
|
+
'data-type': attributes.type
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
uniqueKey: {
|
|
71
|
+
default: '',
|
|
72
|
+
parseHTML: function parseHTML(element) {
|
|
73
|
+
return element.getAttribute('data-unique-key');
|
|
74
|
+
},
|
|
75
|
+
renderHTML: function renderHTML(attributes) {
|
|
76
|
+
return {
|
|
77
|
+
'data-unique-key': attributes.uniqueKey
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
// !!! Very important, affects the cursor size before and after custom nodes
|
|
82
|
+
// Please be sure to add this logic to custom nodes
|
|
83
|
+
isCustomSlot: AIChatInput.getCustomSlotAttribute()
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
parseHTML: function parseHTML() {
|
|
87
|
+
return [{
|
|
88
|
+
tag: 'refer-slot'
|
|
89
|
+
}];
|
|
90
|
+
},
|
|
91
|
+
renderHTML: function renderHTML(_ref) {
|
|
92
|
+
var HTMLAttributes = _ref.HTMLAttributes;
|
|
93
|
+
// 序列化时输出自定义标签,保留值到 data-value
|
|
94
|
+
return ['refer-slot', mergeAttributes(HTMLAttributes)];
|
|
95
|
+
},
|
|
96
|
+
addNodeView: function addNodeView() {
|
|
97
|
+
return ReactNodeViewRenderer(ReferSlotComponent);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
export default ReferSlot;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SkillItem {
|
|
2
|
+
icon?: string;
|
|
3
|
+
key: string;
|
|
4
|
+
type: string;
|
|
5
|
+
name: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const TestAction: Record<string, SkillItem[]>;
|
|
9
|
+
export declare const FirstLevel: string[];
|
|
10
|
+
export declare const SkillList: SkillItem[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IconFile, IconFolder, IconBranch, IconCode, IconGit } from '@douyinfe/semi-icons';
|
|
3
|
+
// 面板选项(按分组组织)
|
|
4
|
+
export var TestAction = {
|
|
5
|
+
'Files & Folders': [{
|
|
6
|
+
icon: /*#__PURE__*/React.createElement(IconFile, null),
|
|
7
|
+
key: '1-1',
|
|
8
|
+
type: 'file',
|
|
9
|
+
name: 'TagInput.scss',
|
|
10
|
+
path: 'package/semi-founctaion/TagInput.scss'
|
|
11
|
+
}, {
|
|
12
|
+
icon: /*#__PURE__*/React.createElement(IconFolder, null),
|
|
13
|
+
key: '1-2',
|
|
14
|
+
type: 'folder',
|
|
15
|
+
name: 'package',
|
|
16
|
+
path: '/package'
|
|
17
|
+
}, {
|
|
18
|
+
icon: /*#__PURE__*/React.createElement(IconFolder, null),
|
|
19
|
+
key: '1-3',
|
|
20
|
+
type: 'folder',
|
|
21
|
+
name: 'semi-ui',
|
|
22
|
+
path: '/package/semi-ui'
|
|
23
|
+
}],
|
|
24
|
+
Git: [{
|
|
25
|
+
icon: /*#__PURE__*/React.createElement(IconBranch, null),
|
|
26
|
+
key: '2-1',
|
|
27
|
+
type: 'branch',
|
|
28
|
+
name: 'fix/tag'
|
|
29
|
+
}, {
|
|
30
|
+
icon: /*#__PURE__*/React.createElement(IconCode, null),
|
|
31
|
+
key: '2-2',
|
|
32
|
+
type: 'code',
|
|
33
|
+
name: 'v2.86.0',
|
|
34
|
+
path: '/package'
|
|
35
|
+
}, {
|
|
36
|
+
icon: /*#__PURE__*/React.createElement(IconGit, null),
|
|
37
|
+
key: '2-3',
|
|
38
|
+
type: 'git',
|
|
39
|
+
name: 'chore: publish'
|
|
40
|
+
}]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// 第一级内容
|
|
44
|
+
export var FirstLevel = Object.keys(TestAction);
|
|
45
|
+
|
|
46
|
+
// 扁平化所有选项,用于单层面板直接展示
|
|
47
|
+
export var SkillList = FirstLevel.reduce(function (acc, key) {
|
|
48
|
+
return acc.concat(TestAction[key] || []);
|
|
49
|
+
}, []);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import ReferSlot from './ReferSlot';
|
|
2
|
+
import SkillMention from './suggestion';
|
|
3
|
+
export { ReferSlot, SkillMention };
|
|
4
|
+
export { suggestion, setSkillContext } from './suggestion';
|
|
5
|
+
export { TestAction, FirstLevel } from './data';
|
|
6
|
+
export type { SkillItem } from './data';
|
|
7
|
+
export type { SkillCommandProps } from './suggestion';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
.ai-chat-input-custom-extension-dropdown-menu {
|
|
2
|
+
background: #fff;
|
|
3
|
+
border: 1px solid #E3E3E1;
|
|
4
|
+
border-radius: 20px;
|
|
5
|
+
box-shadow: 0 2px 32px 0 rgba(0, 0, 0, 0.10);
|
|
6
|
+
padding: 10px;
|
|
7
|
+
max-height: 300px;
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
.ai-chat-input-custom-extension-dropdown-wrap {
|
|
10
|
+
overflow-y: auto;
|
|
11
|
+
max-height: 240px;
|
|
12
|
+
padding-right: 14px;
|
|
13
|
+
|
|
14
|
+
&::-webkit-scrollbar {
|
|
15
|
+
width: 6px;
|
|
16
|
+
}
|
|
17
|
+
&::-webkit-scrollbar-thumb {
|
|
18
|
+
background-color: #EDEDEB;
|
|
19
|
+
border-radius: 4px;
|
|
20
|
+
}
|
|
21
|
+
&::-webkit-scrollbar-track {
|
|
22
|
+
background: transparent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
.optionItem {
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
padding: 0 10px;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
font-size: 14px;
|
|
31
|
+
height: 30px;
|
|
32
|
+
border-radius: 10px;
|
|
33
|
+
margin-bottom: 6px;
|
|
34
|
+
&:last-child {
|
|
35
|
+
margin-bottom: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&:hover,
|
|
39
|
+
&.is-selected {
|
|
40
|
+
background: var(--theme-lightNeutral, #EDEDEB);
|
|
41
|
+
}
|
|
42
|
+
.name {
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.skillTitle {
|
|
49
|
+
color: var(--theme-mediumNeutral, #B3B2B2);
|
|
50
|
+
font-size: 12px;
|
|
51
|
+
font-weight: 500;
|
|
52
|
+
line-height: 21px;
|
|
53
|
+
margin-bottom: 3px;
|
|
54
|
+
padding-left: 5px;
|
|
55
|
+
}
|
|
56
|
+
.skillItem {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
width: 100%;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
.icon {
|
|
62
|
+
width: 14px;
|
|
63
|
+
height: 14px;
|
|
64
|
+
margin-right: 8px;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
}
|
|
67
|
+
.name {
|
|
68
|
+
font-size: 14px;
|
|
69
|
+
margin-right: 4px;
|
|
70
|
+
color: var(--theme-deepNeutral, #221813);
|
|
71
|
+
white-space: nowrap;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
text-overflow: ellipsis;
|
|
74
|
+
}
|
|
75
|
+
.toolDesc {
|
|
76
|
+
font-size: 12px;
|
|
77
|
+
color: var(--theme-dustyNeutral, #878786);
|
|
78
|
+
flex: 1;
|
|
79
|
+
min-width: 0;
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
text-overflow: ellipsis;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.item {
|
|
87
|
+
padding: 20px 12px;
|
|
88
|
+
color: var(--theme-dustyNeutral, #878786);
|
|
89
|
+
font-size: 14px;
|
|
90
|
+
text-align: center;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.ai-chat-input-refer-slot-wrapper {
|
|
95
|
+
display: inline-block;
|
|
96
|
+
border-radius: 10px;
|
|
97
|
+
background:#E3E3E1;
|
|
98
|
+
padding: 0 8px;
|
|
99
|
+
line-height: 23px;
|
|
100
|
+
margin-right: 6px;
|
|
101
|
+
margin-bottom: 4px;
|
|
102
|
+
.ai-chat-input-refer-slot {
|
|
103
|
+
font-size: 14px;
|
|
104
|
+
color: var(--theme-deepNeutral, #221813);
|
|
105
|
+
font-weight: 500;
|
|
106
|
+
vertical-align: middle;
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
.ai-chat-input-refer-slot-image {
|
|
110
|
+
width: 14px;
|
|
111
|
+
height: 14px;
|
|
112
|
+
margin-right: 4px;
|
|
113
|
+
flex-shrink: 0;
|
|
114
|
+
vertical-align: middle;
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SkillItem } from './MentionList';
|
|
2
|
+
import type { IUseApi } from '../../../../apis/useApi';
|
|
3
|
+
export interface SkillCommandProps {
|
|
4
|
+
item?: SkillItem;
|
|
5
|
+
allowHotKeySend?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare let skillContext: {
|
|
8
|
+
getAgentId?: () => number | undefined;
|
|
9
|
+
getApiService?: () => IUseApi | null;
|
|
10
|
+
getSkillDisplay?: () => number | undefined;
|
|
11
|
+
getCurrentTextLength?: () => number;
|
|
12
|
+
};
|
|
13
|
+
export declare const setSkillContext: (ctx: Partial<typeof skillContext>) => void;
|
|
14
|
+
export declare const suggestion: any;
|
|
15
|
+
declare const SkillMention: import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any>;
|
|
16
|
+
export default SkillMention;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
5
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
6
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
import { ReactRenderer } from '@tiptap/react';
|
|
8
|
+
import Mention from '@tiptap/extension-mention';
|
|
9
|
+
import { SkillList } from "./data";
|
|
10
|
+
import MentionList from "./MentionList";
|
|
11
|
+
|
|
12
|
+
// 选中后面板回传给 command 的结构
|
|
13
|
+
|
|
14
|
+
// 面板预期最大高度,用于估算下方空间是否足够
|
|
15
|
+
var PANEL_MAX_HEIGHT = 300;
|
|
16
|
+
// 面板与输入框的间距
|
|
17
|
+
var PANEL_GAP = 0;
|
|
18
|
+
|
|
19
|
+
// 把面板定位到 AIChatInput 输入框正下方,宽度与输入框一致;
|
|
20
|
+
// 若下方空间不足则翻转到输入框上方显示。
|
|
21
|
+
var positionPanel = function positionPanel(editor, element) {
|
|
22
|
+
var _editor$view;
|
|
23
|
+
if (!element) return null;
|
|
24
|
+
var triggerEl = editor === null || editor === void 0 || (_editor$view = editor.view) === null || _editor$view === void 0 || (_editor$view = _editor$view.dom) === null || _editor$view === void 0 ? void 0 : _editor$view.closest('.semi-aiChatInput');
|
|
25
|
+
if (!triggerEl) return null;
|
|
26
|
+
var rect = triggerEl.getBoundingClientRect();
|
|
27
|
+
var _window = window,
|
|
28
|
+
scrollX = _window.scrollX,
|
|
29
|
+
scrollY = _window.scrollY,
|
|
30
|
+
innerHeight = _window.innerHeight;
|
|
31
|
+
// 下方剩余空间(视口高度 - 输入框底部)
|
|
32
|
+
var spaceBelow = innerHeight - rect.bottom;
|
|
33
|
+
// 渲染后的实际面板高度,未知时用预期最大高度估算
|
|
34
|
+
var panelHeight = element.offsetHeight || PANEL_MAX_HEIGHT;
|
|
35
|
+
// 下方放得下就放下方,否则翻到上方(输入框顶部之上)
|
|
36
|
+
var placeBelow = spaceBelow >= panelHeight + PANEL_GAP;
|
|
37
|
+
element.style.position = 'absolute';
|
|
38
|
+
element.style.left = "".concat(rect.left + scrollX, "px");
|
|
39
|
+
element.style.width = "".concat(rect.width, "px");
|
|
40
|
+
element.style.boxSizing = 'border-box';
|
|
41
|
+
if (placeBelow) {
|
|
42
|
+
element.style.transform = '';
|
|
43
|
+
element.style.top = "".concat(rect.bottom + scrollY + PANEL_GAP, "px");
|
|
44
|
+
element.style.maxHeight = "".concat(PANEL_MAX_HEIGHT, "px");
|
|
45
|
+
} else {
|
|
46
|
+
// 翻到上方:底部贴输入框顶部(留 GAP)。用 translateY(-100%) 让面板向上偏移自身高度,
|
|
47
|
+
// 不依赖 JS 读取 offsetHeight,避免高度测量不准导致盖到输入框
|
|
48
|
+
var aboveSpace = rect.top - PANEL_GAP;
|
|
49
|
+
element.style.maxHeight = "".concat(Math.min(PANEL_MAX_HEIGHT, aboveSpace), "px");
|
|
50
|
+
element.style.top = "".concat(rect.top + scrollY - PANEL_GAP, "px");
|
|
51
|
+
element.style.transform = 'translateY(-100%)';
|
|
52
|
+
}
|
|
53
|
+
return triggerEl;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// suggestion 配置
|
|
57
|
+
// v3 的 SuggestionOptions 签名与官方 v2 示例有差异(items 为
|
|
58
|
+
// ({query,editor,signal}) => I[],command 的 props 为泛型 TSelected),
|
|
59
|
+
// 因此用 SkillCommandProps 作为 TSelected,并在 Mention.configure 处用 as any 适配。
|
|
60
|
+
// 面板不跟随光标,而是贴在 AIChatInput 输入框下方、与输入框等宽,模拟官方 skillHotKey 面板效果。
|
|
61
|
+
// skill 面板由 tiptap ReactRenderer 渲染,脱离 ChatContext/Redux 树,
|
|
62
|
+
// 故通过此 setter 注入当前 agentId 与 apiService 供 MentionList 拉取接口数据
|
|
63
|
+
var skillContext = {};
|
|
64
|
+
export var setSkillContext = function setSkillContext(ctx) {
|
|
65
|
+
skillContext = _objectSpread(_objectSpread({}, skillContext), ctx);
|
|
66
|
+
};
|
|
67
|
+
export var suggestion = {
|
|
68
|
+
char: '/',
|
|
69
|
+
items: function items() {
|
|
70
|
+
return SkillList;
|
|
71
|
+
},
|
|
72
|
+
command: function command(_ref) {
|
|
73
|
+
var editor = _ref.editor,
|
|
74
|
+
range = _ref.range,
|
|
75
|
+
props = _ref.props;
|
|
76
|
+
var item = props.item,
|
|
77
|
+
allowHotKeySend = props.allowHotKeySend;
|
|
78
|
+
if (typeof allowHotKeySend === 'boolean') {
|
|
79
|
+
var _editor$storage;
|
|
80
|
+
// statusExtension(SemiAIChatInput)默认加载,storage 一定存在
|
|
81
|
+
if ((_editor$storage = editor.storage) !== null && _editor$storage !== void 0 && _editor$storage.SemiAIChatInput) {
|
|
82
|
+
editor.storage.SemiAIChatInput.allowHotKeySend = allowHotKeySend;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
item && editor.chain().focus().insertContentAt(range, {
|
|
86
|
+
type: 'referSlot',
|
|
87
|
+
attrs: {
|
|
88
|
+
type: 'skill',
|
|
89
|
+
value: item.toolName || '',
|
|
90
|
+
info: JSON.stringify({
|
|
91
|
+
toolName: item.toolName || '',
|
|
92
|
+
toolId: item.toolId || '',
|
|
93
|
+
imageUrl: item.imageUrl || '',
|
|
94
|
+
toolType: item.toolCategoryDesc || ''
|
|
95
|
+
}),
|
|
96
|
+
uniqueKey: item.toolId || ''
|
|
97
|
+
}
|
|
98
|
+
}).run();
|
|
99
|
+
},
|
|
100
|
+
render: function render() {
|
|
101
|
+
var component;
|
|
102
|
+
var reposition = null;
|
|
103
|
+
var outsideClickHandler = null;
|
|
104
|
+
var currentEditor = null;
|
|
105
|
+
var currentRange = null;
|
|
106
|
+
var isVisible = true; // 面板当前可见状态
|
|
107
|
+
|
|
108
|
+
// 统一的清理和退出逻辑
|
|
109
|
+
var cleanup = function cleanup() {
|
|
110
|
+
var _component, _component2;
|
|
111
|
+
if (reposition) {
|
|
112
|
+
window.removeEventListener('resize', reposition);
|
|
113
|
+
window.removeEventListener('scroll', reposition, true);
|
|
114
|
+
reposition = null;
|
|
115
|
+
}
|
|
116
|
+
if (outsideClickHandler) {
|
|
117
|
+
document.removeEventListener('mousedown', outsideClickHandler, true);
|
|
118
|
+
outsideClickHandler = null;
|
|
119
|
+
}
|
|
120
|
+
currentEditor = null;
|
|
121
|
+
currentRange = null;
|
|
122
|
+
(_component = component) === null || _component === void 0 || (_component = _component.element) === null || _component === void 0 || _component.remove();
|
|
123
|
+
(_component2 = component) === null || _component2 === void 0 || _component2.destroy();
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// MentionList 通知可见性变化
|
|
127
|
+
var handleVisibilityChange = function handleVisibilityChange(visible) {
|
|
128
|
+
var _component3;
|
|
129
|
+
if (!((_component3 = component) !== null && _component3 !== void 0 && _component3.element)) return;
|
|
130
|
+
isVisible = visible;
|
|
131
|
+
if (visible) {
|
|
132
|
+
component.element.style.display = '';
|
|
133
|
+
positionPanel(currentEditor, component.element);
|
|
134
|
+
} else {
|
|
135
|
+
component.element.style.display = 'none';
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
onStart: function onStart(props) {
|
|
140
|
+
var _skillContext$getSkil, _skillContext;
|
|
141
|
+
console.log('[skill] onStart triggered, query=', props.query);
|
|
142
|
+
// 当前智能体未开启技能(skillDisplay !== 1)时不弹出技能选择面板
|
|
143
|
+
if (((_skillContext$getSkil = (_skillContext = skillContext).getSkillDisplay) === null || _skillContext$getSkil === void 0 ? void 0 : _skillContext$getSkil.call(_skillContext)) !== 1) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
var _skillContext$getAgen, _skillContext2, _skillContext$getApiS, _skillContext$getApiS2, _skillContext3;
|
|
148
|
+
var agentId = (_skillContext$getAgen = (_skillContext2 = skillContext).getAgentId) === null || _skillContext$getAgen === void 0 ? void 0 : _skillContext$getAgen.call(_skillContext2);
|
|
149
|
+
var apiService = (_skillContext$getApiS = (_skillContext$getApiS2 = (_skillContext3 = skillContext).getApiService) === null || _skillContext$getApiS2 === void 0 ? void 0 : _skillContext$getApiS2.call(_skillContext3)) !== null && _skillContext$getApiS !== void 0 ? _skillContext$getApiS : null;
|
|
150
|
+
var getCurrentTextLength = skillContext.getCurrentTextLength;
|
|
151
|
+
currentEditor = props.editor;
|
|
152
|
+
currentRange = props.range;
|
|
153
|
+
component = new ReactRenderer(MentionList, {
|
|
154
|
+
props: _objectSpread(_objectSpread({}, props), {}, {
|
|
155
|
+
agentId: agentId,
|
|
156
|
+
apiService: apiService,
|
|
157
|
+
getCurrentTextLength: getCurrentTextLength,
|
|
158
|
+
onVisibilityChange: handleVisibilityChange
|
|
159
|
+
}),
|
|
160
|
+
editor: props.editor
|
|
161
|
+
});
|
|
162
|
+
component.element.style.position = 'absolute';
|
|
163
|
+
component.element.style.zIndex = '1031';
|
|
164
|
+
document.body.appendChild(component.element);
|
|
165
|
+
positionPanel(props.editor, component.element);
|
|
166
|
+
// 首帧高度可能为 0,下一帧用实测高度二次校正翻转
|
|
167
|
+
requestAnimationFrame(function () {
|
|
168
|
+
return positionPanel(props.editor, component.element);
|
|
169
|
+
});
|
|
170
|
+
// 滚动/resize 时让面板跟随输入框位置
|
|
171
|
+
reposition = function reposition() {
|
|
172
|
+
return positionPanel(props.editor, component.element);
|
|
173
|
+
};
|
|
174
|
+
window.addEventListener('resize', reposition);
|
|
175
|
+
window.addEventListener('scroll', reposition, true);
|
|
176
|
+
outsideClickHandler = function outsideClickHandler(e) {
|
|
177
|
+
var _component4;
|
|
178
|
+
if (!((_component4 = component) !== null && _component4 !== void 0 && _component4.element)) return;
|
|
179
|
+
if (component.element.contains(e.target)) return;
|
|
180
|
+
e.stopPropagation();
|
|
181
|
+
// 手动移除面板 DOM,再通过内容变更让 suggestion plugin 退出
|
|
182
|
+
component.element.remove();
|
|
183
|
+
if (currentEditor && currentRange) {
|
|
184
|
+
var insertPos = currentRange.from;
|
|
185
|
+
currentEditor.chain().focus().deleteRange(currentRange).insertContentAt(insertPos, '/').run();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
document.addEventListener('mousedown', outsideClickHandler, true);
|
|
189
|
+
} catch (e) {
|
|
190
|
+
console.error('[skill] onStart render error:', e);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
onUpdate: function onUpdate(props) {
|
|
194
|
+
if (!component) return;
|
|
195
|
+
currentRange = props.range;
|
|
196
|
+
component.updateProps(props);
|
|
197
|
+
// query 变化导致面板高度变化,只在可见时重新定位
|
|
198
|
+
if (isVisible) {
|
|
199
|
+
positionPanel(props.editor, component.element);
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
onKeyDown: function onKeyDown(props) {
|
|
203
|
+
var _component5, _component5$onKeyDown;
|
|
204
|
+
function onExit() {
|
|
205
|
+
cleanup();
|
|
206
|
+
}
|
|
207
|
+
return (_component5 = component) === null || _component5 === void 0 || (_component5 = _component5.ref) === null || _component5 === void 0 || (_component5$onKeyDown = _component5.onKeyDown) === null || _component5$onKeyDown === void 0 ? void 0 : _component5$onKeyDown.call(_component5, _objectSpread(_objectSpread({}, props), {}, {
|
|
208
|
+
exitCb: onExit
|
|
209
|
+
}));
|
|
210
|
+
},
|
|
211
|
+
onExit: function onExit() {
|
|
212
|
+
cleanup();
|
|
213
|
+
},
|
|
214
|
+
focusEditor: function focusEditor(props) {
|
|
215
|
+
props.editor.commands.focus();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// 配置好的 Mention 扩展(/ 触发)
|
|
222
|
+
var SkillMention = Mention.configure({
|
|
223
|
+
HTMLAttributes: {
|
|
224
|
+
class: 'mention'
|
|
225
|
+
},
|
|
226
|
+
suggestion: suggestion
|
|
227
|
+
});
|
|
228
|
+
export default SkillMention;
|