diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18c219026afe81a183bb7c04fbfc72dd8ba612ed..1e1374b8fb5a02b82b824bc031cb58af14d8d091 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
### Added
- 文件上传、图片上传、图片裁剪上传、html、轮播图、签名、消息占位、文件表格列组件支持启用无权限模式,上传文件夹需拼接'$'字符,也不需要计算下载凭证
+- 新增行内AI工具调用信息
## [0.7.41-alpha.43] - 2025-12-02
diff --git a/src/locale/en/index.ts b/src/locale/en/index.ts
index 62b8d7b03d2210c37f9e032d35b6b7d8aebb7a1c..8ebaf7caaf46c133711fff5a3c1c5022127ef6dd 100644
--- a/src/locale/en/index.ts
+++ b/src/locale/en/index.ts
@@ -904,6 +904,10 @@ export default {
warningDesc: 'Are you sure to terminate the creation?',
thinking: 'In depth thinking',
thinked: 'Deeply pondered',
+ collapseToolCall: 'Retract tool calls',
+ expandToolCall: 'Expand all {number} tool calls',
+ error: 'An error occurred',
+ copy: 'Copied',
},
aiChartUtil: {
feedback: 'Feedback',
diff --git a/src/locale/zh-CN/index.ts b/src/locale/zh-CN/index.ts
index 79b7b27601e08928b659eec6af92644b4ba93e3c..b17ebbbced5eaac790978db5bb5a3b3e16ed188b 100644
--- a/src/locale/zh-CN/index.ts
+++ b/src/locale/zh-CN/index.ts
@@ -848,6 +848,10 @@ export default {
warningDesc: '确认中止创作吗?',
thinking: '深度思考中',
thinked: '已深度思考',
+ collapseToolCall: '收起工具调用',
+ expandToolCall: '展开全部 {number} 个工具调用',
+ error: '发生错误',
+ copy: '已复制',
},
aiChartUtil: {
feedback: '反馈',
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/ai-think/ai-think.scss b/src/util/inline-ai-util/inline-ai-textarea/common/ai-think/ai-think.scss
new file mode 100644
index 0000000000000000000000000000000000000000..7adca947eb407e40bb418484278981adf6841b87
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/ai-think/ai-think.scss
@@ -0,0 +1,48 @@
+@include b(ai-think) {
+ width: 100%;
+ height: auto;
+ font-size: getCssVar(font-size, small);
+ color: getCssVar(inline-ai-textarea-container, color-text-1);
+ @include e(header) {
+ display: flex;
+ gap: getCssVar(spacing, extra-tight);
+ align-items: center;
+ margin-bottom: getCssVar(spacing, tight);
+ cursor: pointer;
+
+ &:hover {
+ color: getCssVar(inline-ai-textarea-container, color-text-hove-1);
+ }
+ @include m(state-icon) {
+ display: flex;
+ align-items: center;
+ color: getCssVar(color, success);
+ @include when(loading) {
+ color: getCssVar(inline-ai-textarea-container, color-loading);
+ }
+ }
+ @include m(collapse-icon) {
+ display: flex;
+ align-items: center;
+ }
+ }
+ @include e(content) {
+ position: relative;
+ padding-left: getCssVar(spacing, tight);
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ transition:
+ height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
+ opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+
+ &::before {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 2px;
+ content: '';
+ background-color: getCssVar(inline-ai-textarea-container, color-border);
+ }
+ }
+}
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/ai-think/ai-think.tsx b/src/util/inline-ai-util/inline-ai-textarea/common/ai-think/ai-think.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..16f2d3313814230d7d7c32f70e85bb242ba31cc3
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/ai-think/ai-think.tsx
@@ -0,0 +1,66 @@
+import { defineComponent } from 'vue';
+import { useNamespace } from '@ibiz-template/vue3-util';
+import { DownIcon, LoadingIcon, ThinkSuccessIcon, UpIcon } from '../../icon';
+import './ai-think.scss';
+
+export const AIThink = defineComponent({
+ props: {
+ think: {
+ type: String,
+ },
+ isLoading: {
+ type: Boolean,
+ required: true,
+ },
+ isCollapse: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ emits: {
+ collapseChange: (_value: boolean) => true,
+ },
+ setup(props, { emit }) {
+ const ns = useNamespace('ai-think');
+
+ /**
+ * @description 折叠变更
+ */
+ const onCollapseChange = (): void => {
+ emit('collapseChange', !props.isCollapse);
+ };
+
+ return {
+ ns,
+ onCollapseChange,
+ };
+ },
+ render() {
+ if (!this.think) return;
+ return (
+
+
+ {!this.isCollapse && (
+
{this.think}
+ )}
+
+ );
+ },
+});
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call-item/ai-tool-call-item.scss b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call-item/ai-tool-call-item.scss
new file mode 100644
index 0000000000000000000000000000000000000000..3ea14f9f9288be98cf092715e781c79733fe0b09
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call-item/ai-tool-call-item.scss
@@ -0,0 +1,110 @@
+$ai-tool-call-item: (
+ bg-primary: #1e1e1e,
+ bg-secondary: #2d2d2d,
+ bg-tertiary: #3c3c3c,
+ text-primary: #d4d4d4,
+ text-secondary: #9cdcfe,
+ text-error: #f44747,
+ text-string: #ce9178,
+ text-boolean: #569cd6,
+ text-property: #9cdcfe,
+ text-number: #b5cea8,
+ accent-primary: #0e639c,
+ accent-error: rgb(244 71 71 / 20%),
+ color-bg: getCssVar(inline-ai-textarea-container, color-bg-1),
+ color-border: getCssVar(inline-ai-textarea-container, color-border),
+);
+
+@include b(ai-tool-call-item) {
+ @include set-component-css-var('ai-tool-call-item', $ai-tool-call-item);
+
+ margin-bottom: getCssVar(spacing, tight);
+ background-color: getCssVar(ai-tool-call-item, color-bg);
+ border: 1px solid getCssVar(ai-tool-call-item, color-border);
+ border-radius: getCssVar(border-radius, small);
+
+ @include e(header) {
+ display: flex;
+ gap: getCssVar(spacing, tight);
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: getCssVar(spacing, tight);
+ }
+
+ @include e(header-left) {
+ display: flex;
+ gap: getCssVar(spacing, tight);
+ align-items: center;
+ @include m(caption) {
+ flex-shrink: 0;
+ }
+ @include m(desc) {
+ flex-grow: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+
+ @include e(header-right) {
+ display: flex;
+ flex-shrink: 0;
+ gap: getCssVar(spacing, tight);
+ align-items: center;
+ @include m(icon) {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ }
+ @include m(error-text) {
+ color: getCssVar(color, danger);
+ }
+ }
+
+ @include e(content) {
+ padding: getCssVar(spacing, tight) 0;
+ }
+
+ @include e(code-line) {
+ display: flex;
+ min-height: 18px;
+ margin-bottom: getCssVar(spacing, base, tight);
+ font-family: Consolas, monospace;
+ font-size: 0.95rem;
+ @include m(line-number) {
+ min-width: 20px;
+ margin-right: 15px;
+ color: getCssVar(color, success);
+ text-align: right;
+ user-select: none;
+ }
+ }
+
+ @include e(property) {
+ color: getCssVar(ai-tool-call-item, text-property);
+ }
+
+ @include e(string) {
+ overflow: hidden;
+ color: getCssVar(ai-tool-call-item, text-string);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ @include e(boolean) {
+ color: getCssVar(ai-tool-call-item, text-boolean);
+ }
+
+ @include e(number) {
+ color: getCssVar(ai-tool-call-item, text-number);
+ }
+
+ @include e('null') {
+ color: getCssVar(ai-tool-call-item, text-boolean);
+ }
+
+ @include e(error) {
+ color: getCssVar(ai-tool-call-item, text-error);
+ }
+}
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call-item/ai-tool-call-item.tsx b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call-item/ai-tool-call-item.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..fd4917fda50fff632a7bb9296bef704704be75bc
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call-item/ai-tool-call-item.tsx
@@ -0,0 +1,198 @@
+import { PropType, defineComponent, ref, onMounted } from 'vue';
+import { useNamespace } from '@ibiz-template/vue3-util';
+import { IChatToolCall } from '../../interface';
+import { CopyIcon, DownIcon, ErrorIcon, RightIcon } from '../../icon';
+import './ai-tool-call-item.scss';
+
+export const AIToolCallItem = defineComponent({
+ props: {
+ toolCall: {
+ type: Object as PropType,
+ required: true,
+ },
+ },
+ setup(props) {
+ const ns = useNamespace('ai-tool-call-item');
+
+ /**
+ * 是否展开
+ */
+ const isExpanded = ref(false);
+
+ /**
+ * @description 处理展开变更
+ */
+ const handleExpandChange = (): void => {
+ isExpanded.value = !isExpanded.value;
+ };
+
+ /**
+ * @description 拷贝
+ */
+ const onCopy = (event: MouseEvent): void => {
+ event.stopPropagation();
+ ibiz.util.text.copy(JSON.stringify(props.toolCall, undefined, 2));
+ ibiz.message.success(ibiz.i18n.t('util.inlineAiUtil.copy'));
+ };
+
+ /**
+ * @description 格式化值
+ * @param {unknown} value
+ * @returns {*} {string}
+ */
+ const formatValue = (value: unknown): string => {
+ if (typeof value === 'string') {
+ // 检查是否是错误消息
+ if (
+ value.includes('Failed') ||
+ value.includes('Error') ||
+ value.includes('ERR_')
+ ) {
+ return `"${value}"`;
+ }
+ return `"${value}"`;
+ }
+ if (typeof value === 'number') {
+ return `${value}`;
+ }
+ if (typeof value === 'boolean') {
+ return `${value}`;
+ }
+ if (value === null) {
+ return `null`;
+ }
+ return '';
+ };
+
+ /**
+ * @description 递归格式化JSON字符串
+ * @param {unknown} data
+ * @param {number} [indentLevel=0]
+ * @returns {*}
+ */
+ const formatJSON = (data: unknown, indentLevel: number = 0) => {
+ const indent = ' '.repeat(indentLevel);
+ const lines = [];
+
+ if (Array.isArray(data)) {
+ if (data.length === 0) {
+ return [`${indent}[]`];
+ }
+
+ lines.push(`${indent}[`);
+
+ data.forEach((item, index) => {
+ const itemLines = formatJSON(item, indentLevel + 1);
+ const comma = index < data.length - 1 ? ',' : '';
+
+ if (typeof item === 'object' && item !== null) {
+ lines.push(...itemLines.slice(0, -1));
+ lines.push(`${itemLines[itemLines.length - 1]}${comma}`);
+ } else {
+ lines.push(`${itemLines[0]}${comma}`);
+ }
+ });
+
+ lines.push(`${indent}]`);
+ } else if (typeof data === 'object' && data !== null) {
+ const keys = Object.keys(data);
+ if (keys.length === 0) {
+ return [`${indent}{}`];
+ }
+
+ lines.push(`${indent}{`);
+
+ keys.forEach((key, index) => {
+ const value = (data as Record)[key];
+ const comma = index < keys.length - 1 ? ',' : '';
+ const keyElement = `"${key}":`;
+
+ if (typeof value === 'object' && value !== null) {
+ const valueLines = formatJSON(value, indentLevel + 1);
+ lines.push(`${indent} ${keyElement} ${valueLines[0].trim()}`);
+
+ if (valueLines.length > 1) {
+ lines.push(...valueLines.slice(1, -1));
+ lines.push(`${valueLines[valueLines.length - 1]}${comma}`);
+ }
+ } else {
+ const valueElement = formatValue(value);
+ lines.push(`${indent} ${keyElement} ${valueElement}${comma}`);
+ }
+ });
+
+ lines.push(`${indent}}`);
+ } else {
+ lines.push(`${indent}${formatValue(data)}`);
+ }
+
+ return lines;
+ };
+
+ const lines = ref([]);
+
+ const onInit = (): void => {
+ const items = formatJSON(props.toolCall, 0);
+ lines.value = items.map(
+ (item, index) =>
+ `${index + 1}${item}`,
+ );
+ };
+
+ onMounted(() => {
+ onInit();
+ });
+
+ return {
+ ns,
+ lines,
+ isExpanded,
+ onCopy,
+ handleExpandChange,
+ };
+ },
+ render() {
+ return (
+
+
+ {this.isExpanded && (
+
+ {this.lines.map(line => {
+ return
;
+ })}
+
+ )}
+
+ );
+ },
+});
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call/ai-tool-call.scss b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call/ai-tool-call.scss
new file mode 100644
index 0000000000000000000000000000000000000000..326932f8f3ab16726f285a598cd3c0c57ffd9438
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call/ai-tool-call.scss
@@ -0,0 +1,17 @@
+@include b(ai-tool-call) {
+ color: getCssVar(inline-ai-textarea-container, color-text-0);
+
+ @include e(toggle) {
+ display: block;
+ padding: getCssVar(spacing, tight) 0;
+ margin-top: getCssVar(spacing, tight);
+ text-align: center;
+ cursor: pointer;
+ background-color: getCssVar(inline-ai-textarea-container, color-bg-1);
+ border-radius: getCssVar(border-radius, small);
+
+ &:hover {
+ background-color: getCssVar(inline-ai-textarea-container, color-bg-hover-1);
+ }
+ }
+}
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call/ai-tool-call.tsx b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call/ai-tool-call.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f148947f6b94e945ca2f3fb45f38ae5c0ab510ad
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/ai-tool-call/ai-tool-call.tsx
@@ -0,0 +1,72 @@
+import { PropType, computed, defineComponent, ref } from 'vue';
+import { useNamespace } from '@ibiz-template/vue3-util';
+import { IChatToolCall } from '../../interface';
+import { AIToolCallItem } from '../ai-tool-call-item/ai-tool-call-item';
+import './ai-tool-call.scss';
+
+export const AIToolCall = defineComponent({
+ props: {
+ toolCalls: {
+ type: Object as PropType,
+ required: true,
+ },
+ },
+ setup(props) {
+ const ns = useNamespace('ai-tool-call');
+
+ /**
+ * 是否展开
+ */
+ const isExpanded = ref(false);
+
+ /**
+ * 显示切换
+ */
+ const showToggle = computed(() => {
+ return props.toolCalls.length > 4;
+ });
+
+ /**
+ * 调用工具
+ */
+ const items = computed(() => {
+ return showToggle.value && !isExpanded.value
+ ? props.toolCalls.slice(0, 4)
+ : props.toolCalls;
+ });
+
+ /**
+ * @description 处理切换
+ */
+ const handleToggle = (): void => {
+ isExpanded.value = !isExpanded.value;
+ };
+
+ return {
+ ns,
+ items,
+ showToggle,
+ isExpanded,
+ handleToggle,
+ };
+ },
+ render() {
+ if (!this.toolCalls.length) return;
+ return (
+
+ {this.items.map(item => {
+ return
;
+ })}
+ {this.showToggle && (
+
+ {this.isExpanded
+ ? ibiz.i18n.t('util.inlineAiUtil.collapseToolCall')
+ : ibiz.i18n.t('util.inlineAiUtil.expandToolCall', {
+ number: this.toolCalls.length,
+ })}
+
+ )}
+
+ );
+ },
+});
diff --git a/src/util/inline-ai-util/inline-ai-textarea/common/index.ts b/src/util/inline-ai-util/inline-ai-textarea/common/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..717231ee887985b8b622c78f3ea00e02b3dc684b
--- /dev/null
+++ b/src/util/inline-ai-util/inline-ai-textarea/common/index.ts
@@ -0,0 +1,2 @@
+export { AIThink } from './ai-think/ai-think';
+export { AIToolCall } from './ai-tool-call/ai-tool-call';
diff --git a/src/util/inline-ai-util/inline-ai-textarea/icon.tsx b/src/util/inline-ai-util/inline-ai-textarea/icon.tsx
index d53a33627102963ff8437eff04d3ad89a6716885..cdf47f5aaef50e0d16454044d03dcb7d6fba8667 100644
--- a/src/util/inline-ai-util/inline-ai-textarea/icon.tsx
+++ b/src/util/inline-ai-util/inline-ai-textarea/icon.tsx
@@ -294,3 +294,64 @@ export const DownIcon = (
);
+/**
+ * 向右图标
+ */
+export const RightIcon = (
+
+);
+/**
+ * 错误图标
+ */
+export const ErrorIcon = (
+
+);
+
+/**
+ * 拷贝图标
+ */
+export const CopyIcon = (
+
+);
diff --git a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.hook.ts b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.hook.ts
index 69cd0104ca06de7e26048bac7defd55a1aa2bedd..d001431cf471930544ae4444bd087380544d8c8e 100644
--- a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.hook.ts
+++ b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.hook.ts
@@ -1,5 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/ban-types */
+/* eslint-disable prefer-regex-literals */
+/* eslint-disable no-restricted-syntax */
+/* eslint-disable no-useless-escape */
import qs from 'qs';
import { notNilEmpty } from 'qx-util';
import { useUIStore } from '@ibiz-template/vue3-util';
@@ -22,49 +25,7 @@ import {
RegenerateIcon,
ReplaceTextIcon,
} from './icon';
-
-export interface IAnswer {
- /**
- * @description 回答状态
- * @type {(10 | 20 | 30 | 40)} (未开始 | 回答中 | 回答完成 | 回答错误)
- * @memberof IAnswer
- */
- state: 10 | 20 | 30 | 40;
-
- /**
- * @description 回答内容
- * @type {string}
- * @memberof IAnswer
- */
- content: string;
-}
-
-export interface IMessage {
- /**
- * @description 内容信息
- * @type {string}
- * @memberof IMessage
- */
- content?: string;
- /**
- * @description 错误信息
- * @type {string}
- * @memberof IMessage
- */
- error?: string;
- /**
- * @description 思考信息
- * @type {string}
- * @memberof IMessage
- */
- think?: string;
- /**
- * @description 消息角色
- * @type {('USER' | 'ASSISTANT')}
- * @memberof IMessage
- */
- role: 'USER' | 'ASSISTANT';
-}
+import { IAnswer, IChatToolCall, IMessage } from './interface';
/**
* @description 计算参数
@@ -186,6 +147,7 @@ export const useAI = (
parseContent: (text?: string) => {
think: string | undefined;
content: string | undefined;
+ toolcalls: IChatToolCall[];
};
loadAiHistory: () => Promise;
} => {
@@ -310,7 +272,8 @@ export const useAI = (
const parseContent = (text?: string) => {
let think: string | undefined;
let content: string | undefined;
- if (!text) return { think, content };
+ const toolcalls: IChatToolCall[] = [];
+ if (!text) return { think, content, toolcalls };
const openThinkIndex = text.indexOf('');
const closeThinkIndex = text.indexOf('');
// 如果存在思考过程则解析思考内容
@@ -322,9 +285,32 @@ export const useAI = (
content =
closeThinkIndex === -1 ? undefined : text.slice(closeThinkIndex + 8);
} else {
- content = text;
+ const toolCallRegex = new RegExp(
+ '\\s*({[\\s\\S]*?})\\s*',
+ 'g',
+ );
+ const matches = text.matchAll(toolCallRegex);
+ for (const match of matches) {
+ try {
+ const toolCallData = JSON.parse(match[1]);
+ const tempToolCall = {
+ name: toolCallData.name,
+ parameters: toolCallData.parameters,
+ error: toolCallData.error || false,
+ };
+ if (toolCallData.result)
+ Object.assign(tempToolCall, {
+ result: toolCallData.result,
+ });
+ toolcalls.push(tempToolCall);
+ } catch (e) {
+ console.error('解析工具调用失败:', e);
+ }
+ }
+ // 清除文本调用信息
+ content = text.replace(/\[^]*?\<\/tool_call\>/gs, '').trim();
}
- return { think, content };
+ return { think, content, toolcalls };
};
/**
@@ -543,6 +529,9 @@ export const useBase = (
textareaRef.value.style.height = `${textareaRef.value.scrollHeight}px`;
});
},
+ {
+ immediate: true,
+ },
);
/**
diff --git a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss
index c4dd81f462285a555896d0364443c95f9f091e32..f84289e32def6fd2180e8cda093b181bdde83c50 100644
--- a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss
+++ b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.scss
@@ -77,12 +77,14 @@ $inline-ai-textarea-container: (
.#{bem(inline-ai-textarea-container, content)} {
border: none;
- border-radius: getCssVar(border-radius, small) getCssVar(border-radius, small) 0 0;
+ border-radius: getCssVar(border-radius, small)
+ getCssVar(border-radius, small) 0 0;
box-shadow: none;
}
.#{bem(inline-ai-textarea-container, footer)} {
- border-radius: 0 0 getCssVar(border-radius, small) getCssVar(border-radius, small);
+ border-radius: 0 0 getCssVar(border-radius, small)
+ getCssVar(border-radius, small);
}
}
@@ -103,7 +105,6 @@ $inline-ai-textarea-container: (
display: flex;
flex-direction: column;
flex-grow: 1;
- gap: getCssVar(spacing, tight);
overflow-y: auto;
textarea {
@@ -115,7 +116,9 @@ $inline-ai-textarea-container: (
background-color: getCssVar(inline-ai-textarea-container, color-bg-0);
border: none;
outline: none;
- transition: height .3s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1);
+ transition:
+ height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
+ opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:disabled {
background-color: getCssVar(inline-ai-textarea-container, color-bg-0);
@@ -144,8 +147,10 @@ $inline-ai-textarea-container: (
border-radius: getCssVar(spacing, extra, tight);
&:hover {
- background-color: getCssVar(inline-ai-textarea-container,
- color-bg-hover-1);
+ background-color: getCssVar(
+ inline-ai-textarea-container,
+ color-bg-hover-1
+ );
}
}
@@ -189,7 +194,10 @@ $inline-ai-textarea-container: (
cursor: pointer;
&:hover {
- background-color: getCssVar(inline-ai-textarea-container, color-bg-hover-2);
+ background-color: getCssVar(
+ inline-ai-textarea-container,
+ color-bg-hover-2
+ );
}
@include when(danger) {
@@ -201,7 +209,8 @@ $inline-ai-textarea-container: (
@include m(divider) {
margin: getCssVar(spacing, extra, tight) getCssVar(spacing, base, loose);
- border-top: 1px solid getCssVar(inline-ai-textarea-container, color-border);
+ border-top: 1px solid
+ getCssVar(inline-ai-textarea-container, color-border);
}
}
@@ -212,50 +221,12 @@ $inline-ai-textarea-container: (
@include e(think) {
flex-shrink: 0;
- width: 100%;
- height: auto;
- font-size: getCssVar(font-size, small);
- color: getCssVar(inline-ai-textarea-container, color-text-1);
- @include m(header) {
- display: flex;
- gap: getCssVar(spacing, extra-tight);
- align-items: center;
- margin-bottom: getCssVar(spacing, tight);
- cursor: pointer;
+ margin-bottom: getCssVar(spacing, tight);
+ }
- &:hover {
- color: getCssVar(inline-ai-textarea-container, color-text-hove-1);
- }
- }
- @include m(state-icon) {
- display: flex;
- align-items: center;
- color: getCssVar(color, success);
- @include when(loading) {
- color: getCssVar(inline-ai-textarea-container, color-loading);
- }
- }
- @include m(collapse-icon) {
- display: flex;
- align-items: center;
- }
- @include m(content) {
- position: relative;
- padding-left: getCssVar(spacing, tight);
- word-wrap: break-word;
- white-space: pre-wrap;
- transition: height .3s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1);
-
- &::before {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 2px;
- content: "";
- background-color: getCssVar(inline-ai-textarea-container, color-border);;
- }
- }
+ @include e(tool-call) {
+ flex-shrink: 0;
+ margin-bottom: getCssVar(spacing, tight);
}
@include e(loading) {
@@ -297,4 +268,4 @@ $inline-ai-textarea-container: (
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.tsx b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.tsx
index 3dd91ef06e0c7d20e28713ed1a66c88a5247fe63..9c3e9b0fa181d62d6d3dd70a7313593f3b022d11 100644
--- a/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.tsx
+++ b/src/util/inline-ai-util/inline-ai-textarea/inline-ai-textarea.tsx
@@ -6,21 +6,13 @@ import { useNamespace } from '@ibiz-template/vue3-util';
import { IInLineAiChatOptions } from '@ibiz-template/runtime';
import {
useAI,
- IAnswer,
useBase,
- IMessage,
computedInLineAIParams,
useInLineAIContainerClick,
} from './inline-ai-textarea.hook';
-import {
- AIIcon,
- UpIcon,
- SendIcon,
- StopIcon,
- DownIcon,
- LoadingIcon,
- ThinkSuccessIcon,
-} from './icon';
+import { AIIcon, SendIcon, StopIcon } from './icon';
+import { IAnswer, IMessage } from './interface';
+import { AIToolCall, AIThink } from './common';
import './inline-ai-textarea.scss';
export const InlineAITextArea = defineComponent({
@@ -92,6 +84,7 @@ export const InlineAITextArea = defineComponent({
*/
const message = ref({
role: 'USER',
+ toolcalls: [],
error: undefined,
think: undefined,
content: props.content,
@@ -179,14 +172,17 @@ export const InlineAITextArea = defineComponent({
break;
case 30:
answerContent = answer.content;
- Object.assign(message.value, parseContent(answerContent));
+ const { think, content } = parseContent(answerContent);
+ // 完成时只更新思考和内容
+ Object.assign(message.value, { think, content });
break;
case 40:
isCollapse.value = true;
Object.assign(message.value, {
- error: answer.content,
+ toolcalls: [],
think: undefined,
content: undefined,
+ error: answer.content,
});
break;
default:
@@ -213,6 +209,7 @@ export const InlineAITextArea = defineComponent({
// 重置数据
answerContent = undefined;
Object.assign(message.value, {
+ toolcalls: [],
error: undefined,
think: undefined,
content: undefined,
@@ -244,13 +241,6 @@ export const InlineAITextArea = defineComponent({
}
};
- /**
- * @description 折叠变更
- */
- const onCollapseChange = (): void => {
- isCollapse.value = !isCollapse.value;
- };
-
/**
* @description 处理行为
* @param {MouseEvent} e
@@ -312,35 +302,9 @@ export const InlineAITextArea = defineComponent({
* @description 绘制内容
* @returns {*}
*/
- const renderContent = () => {
+ const renderError = () => {
if (message.value.error)
return {message.value.error}
;
- if (message.value.think)
- return (
-
-
-
- {isLoading.value ? LoadingIcon : ThinkSuccessIcon}
-
-
- {isLoading.value
- ? ibiz.i18n.t('util.inlineAiUtil.thinking')
- : ibiz.i18n.t('util.inlineAiUtil.thinked')}
-
-
- {isCollapse.value ? DownIcon : UpIcon}
-
-
- {!isCollapse.value && (
-
{message.value.think}
- )}
-
- );
};
return {
@@ -351,6 +315,7 @@ export const InlineAITextArea = defineComponent({
message,
disabled,
isLoading,
+ isCollapse,
actionsRef,
textareaRef,
actionStyle,
@@ -358,10 +323,10 @@ export const InlineAITextArea = defineComponent({
contentStyle,
containerStyle,
onKeydown,
+ renderError,
sendQuestion,
handleAction,
renderLoading,
- renderContent,
stopQuestionAndClose,
};
},
@@ -384,7 +349,20 @@ export const InlineAITextArea = defineComponent({
)}
{this.renderLoading()}
- {this.renderContent()}
+
+
{
+ this.isCollapse = val;
+ }}
+ />
+ {this.renderError()}