mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
fix: show errors in execution details
This commit is contained in:
@@ -7,6 +7,7 @@ const props = defineProps<{
|
||||
recordId?: number
|
||||
duration?: number | undefined
|
||||
totalTokens?: number | undefined
|
||||
error?: string
|
||||
}>()
|
||||
const chatConfig = useChatConfigStore()
|
||||
const showLogBtn = chatConfig.getShowLog
|
||||
@@ -28,7 +29,7 @@ function getLogList() {
|
||||
{{ $t('parameter.execution_details') }}
|
||||
</div>
|
||||
</div>
|
||||
<ExecutionDetails ref="executionDetailsRef"></ExecutionDetails>
|
||||
<ExecutionDetails ref="executionDetailsRef" :error="error"></ExecutionDetails>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -17,6 +17,10 @@ import LogChooseTable from './execution-component/LogChooseTable.vue'
|
||||
import LogGeneratePicture from './execution-component/LogGeneratePicture.vue'
|
||||
import LogWithAi from '@/views/chat/execution-component/LogWithAi.vue'
|
||||
|
||||
defineProps<{
|
||||
error?: string
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const logHistory = ref<ChatLogHistory>({})
|
||||
const dialogFormVisible = ref(false)
|
||||
@@ -113,13 +117,29 @@ defineExpose({
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="expandIds.includes(index)" class="content">
|
||||
<LogTerm v-if="ele.operate_key === 'FILTER_TERMS'" :item="ele" />
|
||||
<LogSQLSample v-else-if="ele.operate_key === 'FILTER_SQL_EXAMPLE'" :item="ele" />
|
||||
<LogCustomPrompt v-else-if="ele.operate_key === 'FILTER_CUSTOM_PROMPT'" :item="ele" />
|
||||
<LogChooseTable v-else-if="ele.operate_key === 'CHOOSE_TABLE'" :item="ele" />
|
||||
<LogDataQuery v-else-if="ele.operate_key === 'EXECUTE_SQL'" :item="ele" />
|
||||
<LogGeneratePicture v-else-if="ele.operate_key === 'GENERATE_PICTURE'" :item="ele" />
|
||||
<LogWithAi v-else :item="ele" />
|
||||
<LogTerm v-if="ele.operate_key === 'FILTER_TERMS'" :item="ele" :error="error" />
|
||||
<LogSQLSample
|
||||
v-else-if="ele.operate_key === 'FILTER_SQL_EXAMPLE'"
|
||||
:item="ele"
|
||||
:error="error"
|
||||
/>
|
||||
<LogCustomPrompt
|
||||
v-else-if="ele.operate_key === 'FILTER_CUSTOM_PROMPT'"
|
||||
:item="ele"
|
||||
:error="error"
|
||||
/>
|
||||
<LogChooseTable
|
||||
v-else-if="ele.operate_key === 'CHOOSE_TABLE'"
|
||||
:item="ele"
|
||||
:error="error"
|
||||
/>
|
||||
<LogDataQuery v-else-if="ele.operate_key === 'EXECUTE_SQL'" :item="ele" :error="error" />
|
||||
<LogGeneratePicture
|
||||
v-else-if="ele.operate_key === 'GENERATE_PICTURE'"
|
||||
:item="ele"
|
||||
:error="error"
|
||||
/>
|
||||
<LogWithAi v-else :item="ele" :error="error" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -51,7 +51,7 @@ const recordsBeforeCurrentQuestion = computed(() =>
|
||||
<template v-if="item.error">
|
||||
{{ error }}
|
||||
</template>
|
||||
<div class="item-list flex-gap-fallback flex-col">
|
||||
<div v-else class="item-list flex-gap-fallback flex-col">
|
||||
<div class="inner-title">{{ t('chat.log_system') }}</div>
|
||||
<div class="inner-item flex-gap-fallback flex-col">
|
||||
<div class="inner-item-title">
|
||||
|
||||
@@ -244,6 +244,7 @@
|
||||
:record-id="message.record?.id"
|
||||
:duration="message.record?.duration"
|
||||
:total-tokens="message.record?.total_tokens"
|
||||
:error="message.record?.error"
|
||||
/>
|
||||
<ChatToolBar v-if="!message.isTyping" :message="message">
|
||||
<div class="tool-btns">
|
||||
@@ -339,6 +340,7 @@
|
||||
:record-id="message.record?.id"
|
||||
:duration="message.record?.duration"
|
||||
:total-tokens="message.record?.total_tokens"
|
||||
:error="message.record?.error"
|
||||
/>
|
||||
<ChatToolBar v-if="!message.isTyping" :message="message" />
|
||||
</template>
|
||||
@@ -366,6 +368,7 @@
|
||||
:record-id="message.record?.id"
|
||||
:duration="message.record?.duration"
|
||||
:total-tokens="message.record?.total_tokens"
|
||||
:error="message.record?.error"
|
||||
/>
|
||||
<ChatToolBar v-if="!message.isTyping" :message="message" />
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
"""Regression tests for error messages in chat execution details."""
|
||||
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
CHAT_DIR = PROJECT_ROOT / "frontend" / "src" / "views" / "chat"
|
||||
COMPONENT_DIR = CHAT_DIR / "execution-component"
|
||||
|
||||
LOG_COMPONENTS = (
|
||||
"LogChooseTable",
|
||||
"LogCustomPrompt",
|
||||
"LogDataQuery",
|
||||
"LogGeneratePicture",
|
||||
"LogSQLSample",
|
||||
"LogTerm",
|
||||
"LogWithAi",
|
||||
)
|
||||
|
||||
|
||||
def read_source(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
class ExecutionErrorDetailsTestCase(unittest.TestCase):
|
||||
"""Ensure the record error reaches every failed execution step."""
|
||||
|
||||
def test_chat_view_passes_record_error_to_token_time(self) -> None:
|
||||
source = read_source(CHAT_DIR / "index.vue")
|
||||
token_time_tags = re.findall(r"<ChatTokenTime\b.*?/>", source, re.DOTALL)
|
||||
|
||||
self.assertGreater(len(token_time_tags), 0)
|
||||
for tag in token_time_tags:
|
||||
with self.subTest(tag=tag):
|
||||
self.assertIn(':error="message.record?.error"', tag)
|
||||
|
||||
def test_token_time_forwards_error_to_execution_details(self) -> None:
|
||||
source = read_source(CHAT_DIR / "ChatTokenTime.vue")
|
||||
|
||||
self.assertRegex(
|
||||
source,
|
||||
re.compile(r"defineProps<\{.*?error\?: string.*?\}>\(\)", re.DOTALL),
|
||||
)
|
||||
execution_details_tag = re.search(
|
||||
r"<ExecutionDetails\b.*?</ExecutionDetails>", source, re.DOTALL
|
||||
)
|
||||
self.assertIsNotNone(execution_details_tag)
|
||||
self.assertIn(':error="error"', execution_details_tag.group(0))
|
||||
|
||||
def test_execution_details_forwards_error_to_log_components(self) -> None:
|
||||
source = read_source(CHAT_DIR / "ExecutionDetails.vue")
|
||||
|
||||
self.assertRegex(
|
||||
source,
|
||||
re.compile(r"defineProps<\{.*?error\?: string.*?\}>\(\)", re.DOTALL),
|
||||
)
|
||||
for component in LOG_COMPONENTS:
|
||||
with self.subTest(component=component):
|
||||
component_tag = re.search(rf"<{component}\b.*?/>", source, re.DOTALL)
|
||||
self.assertIsNotNone(component_tag)
|
||||
self.assertIn(':error="error"', component_tag.group(0))
|
||||
|
||||
def test_log_components_render_the_forwarded_error(self) -> None:
|
||||
for component in LOG_COMPONENTS:
|
||||
with self.subTest(component=component):
|
||||
source = read_source(COMPONENT_DIR / f"{component}.vue")
|
||||
error_branch = re.search(
|
||||
r'<template v-if="item\.error">\s*(.*?)\s*</template>',
|
||||
source,
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(error_branch)
|
||||
self.assertIn("{{ error }}", error_branch.group(1))
|
||||
|
||||
def test_ai_log_skips_normal_content_after_an_error(self) -> None:
|
||||
source = read_source(COMPONENT_DIR / "LogWithAi.vue")
|
||||
|
||||
self.assertRegex(
|
||||
source,
|
||||
re.compile(
|
||||
r'<template v-if="item\.error">.*?</template>\s*'
|
||||
r'<div v-else class="item-list flex-gap-fallback flex-col">',
|
||||
re.DOTALL,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user