fix: 修复部分ts报错

This commit is contained in:
digua
2025-12-12 23:06:57 +08:00
parent 8c10216aea
commit cfeba6cc30
11 changed files with 110 additions and 99 deletions

View File

@@ -24,6 +24,8 @@ import type {
MergeParams,
MergeResult,
MemberWithStats,
TableSchema,
SQLResult,
} from '../../src/types/chat'
interface TimeFilter {
@@ -67,6 +69,9 @@ interface ChatApi {
getMembers: (sessionId: string) => Promise<MemberWithStats[]>
updateMemberAliases: (sessionId: string, memberId: number, aliases: string[]) => Promise<boolean>
deleteMember: (sessionId: string, memberId: number) => Promise<boolean>
// SQL 实验室
getSchema: (sessionId: string) => Promise<TableSchema[]>
executeSQL: (sessionId: string, sql: string) => Promise<SQLResult>
}
interface Api {

View File

@@ -21,7 +21,7 @@
"build": "electron-vite build",
"build:mac": "npm run build && electron-builder --mac --config electron-builder.yml -p never",
"build:win": "npm run build && electron-builder --win --config electron-builder.yml -p never",
"type-check": "vue-tsc --noEmit",
"type-check": "vue-tsc --noEmit -p tsconfig.web.json",
"postinstall": "electron-rebuild"
},
"dependencies": {

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { AnchorItem } from '@/composables'
const props = withDefaults(
withDefaults(
defineProps<{
/** 锚点配置列表 */
anchors: AnchorItem[]

View File

@@ -171,12 +171,6 @@ function handleDeleteConversation(convId: string) {
}
}
// 格式化时间戳
function formatTimestamp(ts: number): string {
const date = new Date(ts * 1000)
return date.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' })
}
// 初始化
onMounted(async () => {
await checkLLMConfig()

View File

@@ -3,7 +3,7 @@ import { computed } from 'vue'
import dayjs from 'dayjs'
import MarkdownIt from 'markdown-it'
import userAvatar from '@/assets/images/momo.png'
import type { ContentBlock } from '@/composables/useAIChat'
import type { ContentBlock, ToolBlockContent } from '@/composables/useAIChat'
// Props
const props = defineProps<{
@@ -79,7 +79,7 @@ function formatTimeParams(params: Record<string, unknown>): string {
}
// 格式化工具参数显示
function formatToolParams(tool: ContentBlock extends { type: 'tool'; tool: infer T } ? T : never): string {
function formatToolParams(tool: ToolBlockContent): string {
if (!tool.params) return ''
const name = tool.name

View File

@@ -1,5 +1,4 @@
<script setup lang="ts">
import { computed } from 'vue'
import dayjs from 'dayjs'
// Props

View File

@@ -7,7 +7,7 @@ interface Props {
animated?: boolean
}
const props = withDefaults(defineProps<Props>(), {
withDefaults(defineProps<Props>(), {
color: 'from-pink-400 to-pink-600',
height: 8,
showLabel: false,

View File

@@ -60,8 +60,8 @@ onMounted(() => {
unsubscribeProgress = window.mergeApi.onParseProgress(({ filePath, progress }) => {
const file = files.value.find((f) => f.path === filePath)
if (file && file.status === 'pending') {
// 使用 percentage 而不是 progress(更准确)
file.progress = progress.percentage ?? progress.progress ?? 0
// 使用 progress
file.progress = progress.progress ?? 0
// 构建更详细的进度消息
if (progress.messagesProcessed && progress.messagesProcessed > 0) {
file.progressMessage = `已处理 ${progress.messagesProcessed.toLocaleString()} 条消息`
@@ -407,7 +407,7 @@ const file2Name = computed(() => files.value[1]?.name || '文件 2')
<!-- 拖拽上传区域 -->
<FileDropZone multiple :accept="['.json', '.txt']" :disabled="isLoading" @files="handleFileDrop">
<template #default="{ isDragOver, openFileDialog }">
<template #default="{ isDragOver }">
<div
class="flex cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 px-6 py-6 transition-all hover:border-primary-400 hover:bg-primary-50/50 dark:border-gray-600 dark:hover:border-primary-500 dark:hover:bg-primary-900/10"
:class="{

View File

@@ -17,17 +17,19 @@ export interface ToolCallRecord {
params?: Record<string, unknown>
}
export interface ToolBlockContent {
name: string
displayName: string
status: 'running' | 'done' | 'error'
params?: Record<string, unknown>
}
// 内容块类型(用于 AI 消息的流式混合渲染)
export type ContentBlock =
| { type: 'text'; text: string }
| {
type: 'tool'
tool: {
name: string
displayName: string
status: 'running' | 'done' | 'error'
params?: Record<string, unknown>
}
tool: ToolBlockContent
}
// 消息类型
@@ -152,7 +154,6 @@ export function useAIChat(
toolCalls: [], // 工具调用会在这里更新
}
messages.value.push(userMessage)
const userMessageIndex = messages.value.length - 1
console.log('[AI] 已添加用户消息')
// 开始处理
@@ -259,89 +260,98 @@ export function useAIChat(
content: msg.content,
}))
console.log('[AI] 调用 Agent API...', context, 'historyLength:', historyMessages.length, 'chatType:', chatType, 'promptConfig:', currentPromptConfig.value)
console.log(
'[AI] 调用 Agent API...',
context,
'historyLength:',
historyMessages.length,
'chatType:',
chatType,
'promptConfig:',
currentPromptConfig.value
)
// 获取 requestId 和 promise传递历史消息、聊天类型和提示词配置
const { requestId: agentReqId, promise: agentPromise } = window.agentApi.runStream(
content,
context,
(chunk) => {
// 如果已中止或请求 ID 不匹配,忽略后续 chunks
if (isAborted || thisRequestId !== currentRequestId) {
console.log('[AI] 已中止或请求已过期,忽略 chunk', {
isAborted,
thisRequestId,
currentRequestId,
})
return
}
// 如果已中止或请求 ID 不匹配,忽略后续 chunks
if (isAborted || thisRequestId !== currentRequestId) {
console.log('[AI] 已中止或请求已过期,忽略 chunk', {
isAborted,
thisRequestId,
currentRequestId,
})
return
}
// 只在工具调用时记录,减少日志噪音
if (chunk.type === 'tool_start' || chunk.type === 'tool_result') {
console.log('[AI] Agent chunk:', chunk.type, chunk.toolName)
}
// 只在工具调用时记录,减少日志噪音
if (chunk.type === 'tool_start' || chunk.type === 'tool_result') {
console.log('[AI] Agent chunk:', chunk.type, chunk.toolName)
}
switch (chunk.type) {
case 'content':
// 流式内容更新 - 追加到 contentBlocks
if (chunk.content) {
currentToolStatus.value = null
appendTextToBlocks(chunk.content)
}
break
case 'tool_start':
// 工具开始执行 - 添加工具块到 contentBlocks
console.log('[AI] 工具开始执行:', chunk.toolName, chunk.toolParams)
if (chunk.toolName) {
const toolParams = chunk.toolParams as Record<string, unknown> | undefined
currentToolStatus.value = {
name: chunk.toolName,
displayName: TOOL_DISPLAY_NAMES[chunk.toolName] || chunk.toolName,
status: 'running',
switch (chunk.type) {
case 'content':
// 流式内容更新 - 追加到 contentBlocks
if (chunk.content) {
currentToolStatus.value = null
appendTextToBlocks(chunk.content)
}
toolsUsedInCurrentRound.value.push(chunk.toolName)
break
// 添加工具块到 AI 消息的 contentBlocks
addToolBlock(chunk.toolName, toolParams)
}
break
case 'tool_start':
// 工具开始执行 - 添加工具块到 contentBlocks
console.log('[AI] 工具开始执行:', chunk.toolName, chunk.toolParams)
if (chunk.toolName) {
const toolParams = chunk.toolParams as Record<string, unknown> | undefined
currentToolStatus.value = {
name: chunk.toolName,
displayName: TOOL_DISPLAY_NAMES[chunk.toolName] || chunk.toolName,
status: 'running',
}
toolsUsedInCurrentRound.value.push(chunk.toolName)
case 'tool_result':
// 工具执行结果 - 更新工具块状态
console.log('[AI] 工具执行结果:', chunk.toolName, chunk.toolResult)
if (chunk.toolName) {
if (currentToolStatus.value?.name === chunk.toolName) {
// 添加工具块到 AI 消息的 contentBlocks
addToolBlock(chunk.toolName, toolParams)
}
break
case 'tool_result':
// 工具执行结果 - 更新工具块状态
console.log('[AI] 工具执行结果:', chunk.toolName, chunk.toolResult)
if (chunk.toolName) {
if (currentToolStatus.value?.name === chunk.toolName) {
currentToolStatus.value = {
...currentToolStatus.value,
status: 'done',
}
}
// 更新 contentBlocks 中的工具块状态
updateToolBlockStatus(chunk.toolName, 'done')
}
isLoadingSource.value = false
break
case 'done':
// 完成
console.log('[AI] Agent 完成')
currentToolStatus.value = null
break
case 'error':
// 错误
console.error('[AI] Agent 错误:', chunk.error)
if (currentToolStatus.value) {
currentToolStatus.value = {
...currentToolStatus.value,
status: 'done',
status: 'error',
}
// 更新对应工具块状态为错误
updateToolBlockStatus(currentToolStatus.value.name, 'error')
}
// 更新 contentBlocks 中的工具块状态
updateToolBlockStatus(chunk.toolName, 'done')
}
isLoadingSource.value = false
break
case 'done':
// 完成
console.log('[AI] Agent 完成')
currentToolStatus.value = null
break
case 'error':
// 错误
console.error('[AI] Agent 错误:', chunk.error)
if (currentToolStatus.value) {
currentToolStatus.value = {
...currentToolStatus.value,
status: 'error',
}
// 更新对应工具块状态为错误
updateToolBlockStatus(currentToolStatus.value.name, 'error')
}
break
}
break
}
},
historyMessages,
chatType,
@@ -458,13 +468,16 @@ export function useAIChat(
const history = await window.aiApi.getMessages(conversationId)
currentConversationId.value = conversationId
console.log('[AI] 从数据库加载的原始消息:', history.map((m) => ({
id: m.id,
role: m.role,
contentLength: m.content?.length,
hasContentBlocks: !!m.contentBlocks,
contentBlocksLength: m.contentBlocks?.length,
})))
console.log(
'[AI] 从数据库加载的原始消息:',
history.map((m) => ({
id: m.id,
role: m.role,
contentLength: m.content?.length,
hasContentBlocks: !!m.contentBlocks,
contentBlocksLength: m.contentBlocks?.length,
}))
)
messages.value = history.map((msg) => ({
id: msg.id,

View File

@@ -196,7 +196,7 @@ function getProgressDetail(): string {
class="w-full max-w-4xl"
@files="handleFileDrop"
>
<template #default="{ isDragOver, openFileDialog }">
<template #default="{ isDragOver }">
<div
class="group relative flex w-full cursor-pointer flex-col items-center justify-center rounded-2xl border-2 border-dashed border-pink-300/50 bg-white/50 px-8 py-8 backdrop-blur-sm transition-all duration-300 hover:border-pink-400 hover:bg-white/80 hover:shadow-lg hover:shadow-pink-500/10 focus:outline-none focus:ring-4 focus:ring-pink-500/20 sm:px-12 sm:py-12 dark:border-pink-700/50 dark:bg-gray-900/50 dark:hover:border-pink-500 dark:hover:bg-gray-900/80"
:class="{

View File

@@ -26,7 +26,7 @@ export const router = createRouter({
history: createWebHashHistory(),
})
router.beforeEach((to, from, next) => {
router.beforeEach((_to, _from, next) => {
next()
})