feat: 全新智能体功能
- 基于先进智能体框架,增加智能体编排功能 - 增加智能体聊天,并对接持久化
This commit is contained in:
@@ -3,9 +3,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Tinyflow as TinyflowNative, TinyflowOptions } from '@tinyflow-ai/ui';
|
||||
import {Tinyflow as TinyflowNative, TinyflowOptions} from '@tinyflow-ai/ui';
|
||||
import '@tinyflow-ai/ui/dist/index.css';
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import {nextTick, onMounted, onUnmounted, ref, useAttrs, watch} from 'vue';
|
||||
|
||||
type TinyflowDataOption = Exclude<TinyflowOptions['data'], string | undefined>;
|
||||
|
||||
const props = defineProps<
|
||||
{
|
||||
@@ -15,7 +17,25 @@ const props = defineProps<
|
||||
>();
|
||||
|
||||
const divRef = ref<HTMLDivElement | null>(null);
|
||||
const attrs = useAttrs();
|
||||
let tinyflow: TinyflowNative | null = null;
|
||||
let mountedDataReady = false;
|
||||
let lastAppliedDataSignature = '';
|
||||
|
||||
function normalizeOptionKey(key: string) {
|
||||
return key.replace(/-([a-z])/g, (_match: string, letter: string) =>
|
||||
letter.toUpperCase(),
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeOptions(source: Record<string, unknown>) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(source).map(([key, value]) => [
|
||||
normalizeOptionKey(key),
|
||||
value,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
// 安全深拷贝工具函数
|
||||
function safeDeepClone<T>(obj: T): T {
|
||||
@@ -36,18 +56,45 @@ function safeDeepClone<T>(obj: T): T {
|
||||
}
|
||||
}
|
||||
|
||||
function createDataSignature(data: unknown) {
|
||||
if (data == null || typeof data === 'string') {
|
||||
return String(data ?? '');
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(data);
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function cloneDataIfChanged(data: TinyflowOptions['data']) {
|
||||
if (data == null || typeof data === 'string') {
|
||||
return null;
|
||||
}
|
||||
const signature = createDataSignature(data);
|
||||
if (signature && signature === lastAppliedDataSignature) {
|
||||
return null;
|
||||
}
|
||||
lastAppliedDataSignature = signature;
|
||||
return safeDeepClone(data as TinyflowDataOption);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (divRef.value) {
|
||||
// 净化 props.data,避免响应式对象或函数污染
|
||||
const cleanedProps = { ...props } as any;
|
||||
const cleanedProps = {
|
||||
...normalizeOptions(attrs),
|
||||
...props,
|
||||
} as any;
|
||||
if ('data' in cleanedProps && cleanedProps.data != null) {
|
||||
cleanedProps.data = safeDeepClone(cleanedProps.data);
|
||||
cleanedProps.data = cloneDataIfChanged(cleanedProps.data);
|
||||
}
|
||||
|
||||
tinyflow = new TinyflowNative({
|
||||
...cleanedProps,
|
||||
element: divRef.value,
|
||||
});
|
||||
mountedDataReady = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -56,6 +103,8 @@ onUnmounted(() => {
|
||||
tinyflow.destroy();
|
||||
tinyflow = null;
|
||||
}
|
||||
mountedDataReady = false;
|
||||
lastAppliedDataSignature = '';
|
||||
});
|
||||
|
||||
watch(
|
||||
@@ -67,6 +116,24 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(data) => {
|
||||
if (
|
||||
tinyflow &&
|
||||
mountedDataReady &&
|
||||
data != null &&
|
||||
typeof data !== 'string'
|
||||
) {
|
||||
const clonedData = cloneDataIfChanged(data);
|
||||
if (clonedData) {
|
||||
tinyflow.updateData(clonedData, { preserveViewport: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
const getData = () => {
|
||||
if (tinyflow) {
|
||||
return tinyflow.getData();
|
||||
@@ -103,10 +170,26 @@ const fitView = async (options?: { duration?: number; padding?: number }) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const updateData = (
|
||||
data: TinyflowOptions['data'],
|
||||
options?: { preserveViewport?: boolean },
|
||||
) => {
|
||||
if (tinyflow && data != null && typeof data !== 'string') {
|
||||
const clonedData = cloneDataIfChanged(data);
|
||||
if (!clonedData) {
|
||||
return true;
|
||||
}
|
||||
return tinyflow.updateData(clonedData, options);
|
||||
}
|
||||
console.warn('Tinyflow instance is not initialized');
|
||||
return false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
getData,
|
||||
getInstance,
|
||||
focusNode,
|
||||
fitView,
|
||||
updateData,
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user