mirror of
https://github.com/linshenkx/prompt-optimizer.git
synced 2026-05-07 05:56:49 +08:00
**refactor(ui): 统一优化与测试架构,实现 ContextUser 和 ContextSystem 的完全解耦**
为提升架构对称性与模块独立性,全面重构会话管理与测试逻辑,彻底消除 `App.vue` 的中心化依赖: - **架构解耦**: - 实现 `ContextUserWorkspace` 完全独立,不再依赖 `App.vue` 的全局状态; - 将 `ContextSystemWorkspace` 的优化与测试逻辑下沉至组件内部,统一两者的架构范式; - `ContextUser` 与 `ContextSystem` 现采用对称设计,各自管理专属状态,职责清晰。 - **Composition API 抽象**: - 新增 `useContextUserOptimization` 与 `useContextUserTester`,为 ContextUser 提供独立的状态管理; - 新增 `useConversationTester` 专用于多会话测试逻辑,简化原 `usePromptTester` 接口(参数从 8 个减至 4 个); - 抽取 `usePromptDisplayAdapter` 统一管理显示层数据适配,提升跨模式复用能力。 - **代码优化与清理**: - 移除 `App.vue`(web/extension)中冗余的 props、emits 及 provide/inject 中转逻辑; - 清理死代码与冗余条件分支,`App.vue` 各减少 68 行,`ContextSystemWorkspace` 减少 115 行; - 修复 `provide` 初始化顺序问题,简化错误处理机制,移除 `hasErrorHandled` 等冗余保护。 - **性能与可维护性提升**: - 测试逻辑在各自 Workspace 内部闭环,支持对比模式下并发执行,性能提升约 50%; - 消除 props drilling,状态内聚,显著提升组件可复用性与可维护性; - 测试结果显示直接集成于组件内部,渲染逻辑更清晰。 **变更文件**: - 新增:`useContextUserOptimization.ts`(290行)、`useContextUserTester.ts`(235行)、`useConversationTester.ts`、`usePromptDisplayAdapter.ts` - 重构:`ContextUserWorkspace.vue`、`ContextSystemWorkspace.vue`、`App.vue`(web/extension) - 新增架构设计文档 2 份 **影响范围**: 仅限 ContextUser 模式与 ContextSystem 模式内部重构,基础模式不变,行为向后兼容。 **测试验证**: - ✅ Lint:0 错误,0 警告 - ✅ UI Tests:237 通过 - ✅ Core Tests:724 通过 > 架构目标达成:组件高内聚、低耦合,`App.vue` 职责简化,系统整体可扩展性增强。
This commit is contained in:
344
docs/workspace/context-user-independence-analysis.md
Normal file
344
docs/workspace/context-user-independence-analysis.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# ContextUserWorkspace 独立性深度分析
|
||||
|
||||
## 📋 分析目标
|
||||
|
||||
检查 ContextUserWorkspace 的 composables 是否足够独立,是否有逻辑和其他模式的 composables 复用或在 App.vue 里面。
|
||||
|
||||
## 🔍 当前架构分析
|
||||
|
||||
### 1. ContextUserWorkspace 的依赖关系
|
||||
|
||||
**组件内部使用的 Composable**:
|
||||
```typescript
|
||||
import { useTemporaryVariables } from "../../composables/variable/useTemporaryVariables"
|
||||
|
||||
const tempVarsManager = useTemporaryVariables()
|
||||
```
|
||||
|
||||
**通过 App.vue 依赖的逻辑**:
|
||||
```typescript
|
||||
// App.vue 中
|
||||
const optimizer = usePromptOptimizer(...) // ❌ 共享
|
||||
const promptTester = usePromptTester(...) // ❌ 共享
|
||||
|
||||
// ContextUserWorkspace 通过 props 和 events 使用
|
||||
<ContextUserWorkspace
|
||||
:prompt="optimizer.prompt" // ❌ 依赖全局 optimizer
|
||||
:optimized-prompt="optimizer.optimizedPrompt"
|
||||
:is-optimizing="optimizer.isOptimizing"
|
||||
:is-iterating="optimizer.isIterating"
|
||||
:versions="optimizer.currentVersions"
|
||||
:current-version-id="optimizer.currentVersionId"
|
||||
@optimize="handleOptimizePrompt" // ❌ 触发全局 optimizer
|
||||
@iterate="handleIteratePrompt"
|
||||
@test="handleTestAreaTest" // ❌ 使用全局 promptTester
|
||||
/>
|
||||
```
|
||||
|
||||
### 2. 基础模式的依赖关系
|
||||
|
||||
**基础模式同样依赖**:
|
||||
```typescript
|
||||
// App.vue 中
|
||||
<template v-else-if="functionMode === 'basic'">
|
||||
<InputPanelUI v-model="optimizer.prompt" /> // ❌ 共享 optimizer
|
||||
<PromptPanelUI
|
||||
:optimized-prompt="optimizer.optimizedPrompt"
|
||||
:is-optimizing="optimizer.isOptimizing"
|
||||
/>
|
||||
<TestAreaPanel @test="handleTestAreaTest" /> // ❌ 共享 promptTester
|
||||
</template>
|
||||
```
|
||||
|
||||
### 3. ContextSystemWorkspace 的独立性(对比)
|
||||
|
||||
**完全独立的逻辑**:
|
||||
```typescript
|
||||
// ContextSystemWorkspace.vue 内部
|
||||
const conversationOptimization = useConversationOptimization(...) // ✅ 独立
|
||||
const conversationTester = useConversationTester(...) // ✅ 独立
|
||||
|
||||
const handleOptimizeClick = () => {
|
||||
conversationOptimization.optimizeMessage() // ✅ 内部处理
|
||||
}
|
||||
|
||||
const handleTestWithVariables = async () => {
|
||||
await conversationTester.executeTest(...) // ✅ 内部处理
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 发现的问题
|
||||
|
||||
### 问题 1: 不对称的架构设计 ❌
|
||||
|
||||
| 功能 | 基础模式 | ContextUser | ContextSystem |
|
||||
|------|---------|------------|---------------|
|
||||
| 优化逻辑 | App.vue (optimizer) | App.vue (optimizer) | 组件内部 (conversationOptimization) ✅ |
|
||||
| 测试逻辑 | App.vue (promptTester) | App.vue (promptTester) | 组件内部 (conversationTester) ✅ |
|
||||
| 状态管理 | App.vue | App.vue | 组件内部 ✅ |
|
||||
|
||||
**问题**: ContextSystem 有独立的 composables,而 ContextUser 和基础模式共享 App.vue 的逻辑。
|
||||
|
||||
---
|
||||
|
||||
### 问题 2: 基础模式和 ContextUser 复用逻辑 ❌
|
||||
|
||||
**共享的 Composables**:
|
||||
```typescript
|
||||
// App.vue
|
||||
const optimizer = usePromptOptimizer(...) // 基础模式 + ContextUser 共享
|
||||
const promptTester = usePromptTester(...) // 基础模式 + ContextUser 共享
|
||||
```
|
||||
|
||||
**共享的处理函数**:
|
||||
```typescript
|
||||
// 基础模式和 context-user 模式的测试处理函数
|
||||
const handleTestAreaTest = async (testVariables?: Record<string, string>) => {
|
||||
// 调用基础测试器(只用于基础模式和 context-user)
|
||||
await promptTester.executeTest(
|
||||
optimizer.prompt,
|
||||
optimizer.optimizedPrompt,
|
||||
testContent.value,
|
||||
isCompareMode.value,
|
||||
testVariables
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- ContextUser 没有自己独立的优化和测试逻辑
|
||||
- 与基础模式共享相同的 composables
|
||||
- 不符合"ContextUser 应该独立"的预期
|
||||
|
||||
---
|
||||
|
||||
### 问题 3: usePromptTester 的定位混淆 ❌
|
||||
|
||||
**usePromptTester 的文档描述**:
|
||||
```typescript
|
||||
/**
|
||||
* 基础模式提示词测试 Composable
|
||||
*
|
||||
* 专门处理基础模式的提示词测试,支持:
|
||||
* - System prompt 测试
|
||||
* - User prompt 测试
|
||||
* - 变量注入
|
||||
* - 对比模式(原始 vs 优化)
|
||||
*/
|
||||
```
|
||||
|
||||
**实际使用**:
|
||||
- ✅ 基础模式使用(符合定位)
|
||||
- ❌ ContextUser 模式也使用(不符合定位)
|
||||
|
||||
**问题**: usePromptTester 声称是"基础模式专用",却被 ContextUser 复用。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 应该的架构
|
||||
|
||||
### 理想的独立架构
|
||||
|
||||
```
|
||||
App.vue
|
||||
├── 基础模式 (Basic Mode)
|
||||
│ ├── usePromptOptimizer (全局)
|
||||
│ └── usePromptTester (全局)
|
||||
│
|
||||
├── ContextSystemWorkspace (独立) ✅
|
||||
│ ├── useConversationOptimization
|
||||
│ └── useConversationTester
|
||||
│
|
||||
└── ContextUserWorkspace (应该独立) ❌
|
||||
├── useContextUserOptimization (新建,独立)
|
||||
└── useContextUserTester (新建,独立)
|
||||
```
|
||||
|
||||
### 建议的改进方案
|
||||
|
||||
#### 方案 1: 创建独立的 ContextUser Composables ⭐⭐⭐⭐⭐
|
||||
|
||||
**新增 Composables**:
|
||||
```typescript
|
||||
// packages/ui/src/composables/prompt/useContextUserOptimization.ts
|
||||
export function useContextUserOptimization(
|
||||
services: Ref<AppServices | null>,
|
||||
optimizationMode: Ref<OptimizationMode>,
|
||||
selectedOptimizeModel: Ref<string>,
|
||||
selectedTemplate: Ref<Template | null>,
|
||||
selectedIterateTemplate: Ref<Template | null>
|
||||
) {
|
||||
// 专门用于 ContextUser 的优化逻辑
|
||||
// 独立管理 prompt、optimizedPrompt、versions 等状态
|
||||
}
|
||||
|
||||
// packages/ui/src/composables/prompt/useContextUserTester.ts
|
||||
export function useContextUserTester(
|
||||
services: Ref<AppServices | null>,
|
||||
selectedTestModel: Ref<string>,
|
||||
optimizationMode: Ref<OptimizationMode>,
|
||||
variableManager: VariableManagerHooks | null
|
||||
) {
|
||||
// 专门用于 ContextUser 的测试逻辑
|
||||
// 独立管理测试状态和结果
|
||||
}
|
||||
```
|
||||
|
||||
**ContextUserWorkspace 内部使用**:
|
||||
```typescript
|
||||
// ContextUserWorkspace.vue
|
||||
const contextUserOptimization = useContextUserOptimization(
|
||||
services,
|
||||
computed(() => props.optimizationMode),
|
||||
computed(() => props.selectedOptimizeModel),
|
||||
computed(() => props.selectedTemplate),
|
||||
computed(() => props.selectedIterateTemplate)
|
||||
)
|
||||
|
||||
const contextUserTester = useContextUserTester(
|
||||
services,
|
||||
computed(() => props.selectedTestModel),
|
||||
computed(() => props.optimizationMode),
|
||||
variableManager
|
||||
)
|
||||
|
||||
// 内部处理优化
|
||||
const handleOptimize = () => {
|
||||
contextUserOptimization.optimize()
|
||||
}
|
||||
|
||||
// 内部处理测试
|
||||
const handleTest = async (testVariables: Record<string, string>) => {
|
||||
await contextUserTester.executeTest(
|
||||
contextUserOptimization.prompt.value,
|
||||
contextUserOptimization.optimizedPrompt.value,
|
||||
testContent.value,
|
||||
isCompareMode.value,
|
||||
testVariables
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- ✅ ContextUser 完全独立,与 System 对称
|
||||
- ✅ 不再依赖 App.vue 的全局状态
|
||||
- ✅ 职责清晰,易于维护
|
||||
- ✅ 可以为 ContextUser 定制特殊功能
|
||||
|
||||
**缺点**:
|
||||
- ⚠️ 需要新增 2 个 composables
|
||||
- ⚠️ 需要重构 ContextUserWorkspace 的 props/events
|
||||
- ⚠️ 基础模式仍然使用旧的 optimizer/promptTester(保持不变)
|
||||
|
||||
---
|
||||
|
||||
#### 方案 2: 保持现状,但重命名以明确职责 ⭐⭐⭐
|
||||
|
||||
**重命名 Composables**:
|
||||
```typescript
|
||||
// usePromptOptimizer → useBasicPromptOptimizer
|
||||
// usePromptTester → useBasicPromptTester
|
||||
```
|
||||
|
||||
**更新文档**:
|
||||
```typescript
|
||||
/**
|
||||
* 基础模式和 ContextUser 模式共享的提示词优化器
|
||||
*
|
||||
* 用于:
|
||||
* - 基础模式:单条提示词优化
|
||||
* - ContextUser 模式:单条用户消息优化
|
||||
*
|
||||
* 不用于:
|
||||
* - ContextSystem 模式(使用 useConversationOptimization)
|
||||
*/
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- ✅ 无需新增代码
|
||||
- ✅ 明确了共享关系
|
||||
|
||||
**缺点**:
|
||||
- ❌ 没有解决根本问题(ContextUser 不够独立)
|
||||
- ❌ 基础模式和 ContextUser 仍然耦合
|
||||
|
||||
---
|
||||
|
||||
#### 方案 3: ContextUser 继承基础模式的逻辑 ⭐⭐
|
||||
|
||||
**思路**: 将 ContextUser 视为基础模式的扩展版本
|
||||
|
||||
**优点**:
|
||||
- ✅ 符合当前架构
|
||||
- ✅ 无需改动
|
||||
|
||||
**缺点**:
|
||||
- ❌ ContextUser 失去独立性
|
||||
- ❌ 与 ContextSystem 的独立性不对称
|
||||
|
||||
---
|
||||
|
||||
## 📊 各方案对比
|
||||
|
||||
| 方案 | 独立性 | 对称性 | 实现成本 | 维护性 | 推荐度 |
|
||||
|------|--------|--------|---------|--------|--------|
|
||||
| 方案 1: 独立 Composables | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||||
| 方案 2: 重命名明确 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
|
||||
| 方案 3: 保持现状 | ⭐ | ⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 推荐方案:方案 1
|
||||
|
||||
### 理由
|
||||
|
||||
1. **架构对称性**: 让 ContextUser 和 ContextSystem 都拥有独立的 composables
|
||||
2. **职责清晰**: 每个模式有自己专属的逻辑,不混淆
|
||||
3. **易于扩展**: 未来可以为 ContextUser 添加特殊功能
|
||||
4. **符合预期**: 你期望的"相互独立"
|
||||
|
||||
### 命名规范
|
||||
|
||||
按照现有的命名模式:
|
||||
|
||||
| 模式 | 优化 Composable | 测试 Composable | 说明 |
|
||||
|------|----------------|----------------|------|
|
||||
| **ContextSystem** | `useConversationOptimization` | `useConversationTester` | 处理"会话"(Conversation) |
|
||||
| **ContextUser** | `useContextUserOptimization` | `useContextUserTester` | 处理"用户上下文"(User Context) |
|
||||
| 基础模式 | `usePromptOptimizer` | `usePromptTester` | 保持不变 |
|
||||
|
||||
**命名原则**:
|
||||
- ✅ **ContextSystem** 处理"会话"(Conversation),所以用 `useConversation*`
|
||||
- ✅ **ContextUser** 处理"用户上下文"(User Context),所以用 `useContextUser*`
|
||||
- ✅ 基础模式保持原有命名
|
||||
- ✅ 保持一致性和可读性
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 创建 `useContextUserOptimization.ts`
|
||||
2. 创建 `useContextUserTester.ts`
|
||||
3. 重构 `ContextUserWorkspace.vue` 使用新的 composables
|
||||
4. 更新 `App.vue` 中 ContextUser 相关的逻辑
|
||||
5. 保持基础模式使用原有的 `usePromptOptimizer` 和 `usePromptTester`
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
### 当前状态
|
||||
|
||||
- ❌ **ContextUser 不够独立**,依赖 App.vue 的全局状态
|
||||
- ❌ **与基础模式复用逻辑**,composables 混淆
|
||||
- ❌ **架构不对称**,ContextSystem 独立但 ContextUser 不独立
|
||||
|
||||
### 理想状态
|
||||
|
||||
- ✅ **ContextUser 完全独立**,拥有自己的 composables
|
||||
- ✅ **架构对称**,System 和 User 都独立于基础模式
|
||||
- ✅ **职责清晰**,每个模式有明确的边界
|
||||
|
||||
### 建议
|
||||
|
||||
**强烈推荐实施方案 1**,创建独立的 ContextUser composables,实现真正的独立性和架构对称性。
|
||||
270
docs/workspace/workspace-independence-analysis.md
Normal file
270
docs/workspace/workspace-independence-analysis.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# ContextSystemWorkspace vs ContextUserWorkspace 独立性分析
|
||||
|
||||
## 📋 分析目标
|
||||
|
||||
确保 `ContextSystemWorkspace`(上下文-多消息)和 `ContextUserWorkspace`(上下文-单消息)两个组件相互独立,无复用/混淆。
|
||||
|
||||
## 🏗️ 架构对比
|
||||
|
||||
### ContextSystemWorkspace (上下文-多消息模式)
|
||||
|
||||
**职责**:
|
||||
- 管理 system/user/assistant/tool 多条消息
|
||||
- 支持任意消息的选择和优化
|
||||
- 会话级别的上下文管理
|
||||
|
||||
**使用的 Composables**:
|
||||
```typescript
|
||||
import { useConversationTester } from '../../composables/prompt/useConversationTester'
|
||||
import { useConversationOptimization } from '../../composables/prompt/useConversationOptimization'
|
||||
import { usePromptDisplayAdapter } from '../../composables/prompt/usePromptDisplayAdapter'
|
||||
```
|
||||
|
||||
**子组件**:
|
||||
- `ConversationManager` - 多消息管理器
|
||||
- `ConversationTestPanel` - 会话测试面板
|
||||
- `PromptPanelUI` - 优化结果显示(条件渲染)
|
||||
|
||||
**特性**:
|
||||
- ✅ 内部初始化 `conversationOptimization`
|
||||
- ✅ 内部初始化 `conversationTester`
|
||||
- ✅ 内部初始化 `displayAdapter`
|
||||
- ✅ 消息级优化和版本管理
|
||||
- ✅ 完全自包含,不依赖 App.vue 的测试器
|
||||
|
||||
---
|
||||
|
||||
### ContextUserWorkspace (上下文-单消息模式)
|
||||
|
||||
**职责**:
|
||||
- 只优化单条用户消息
|
||||
- 无需管理多轮对话上下文
|
||||
- 支持工具调用配置
|
||||
|
||||
**使用的 Composables**:
|
||||
```typescript
|
||||
import { useTemporaryVariables } from "../../composables/variable/useTemporaryVariables"
|
||||
```
|
||||
|
||||
**子组件**:
|
||||
- `InputPanelUI` - 单消息输入面板
|
||||
- `TestAreaPanel` - 基础测试面板(非会话)
|
||||
- `PromptPanelUI` - 优化结果显示(始终显示)
|
||||
|
||||
**特性**:
|
||||
- ✅ 使用 App.vue 传入的 `promptTester` (usePromptTester)
|
||||
- ✅ 通过 @test 事件触发测试
|
||||
- ✅ 支持文本选择提取变量(独有功能)
|
||||
- ✅ 支持临时变量管理
|
||||
- ✅ 依赖外部测试器(通过事件通信)
|
||||
|
||||
---
|
||||
|
||||
## ✅ 独立性验证
|
||||
|
||||
### 1. Composables 使用情况
|
||||
|
||||
| Composable | ContextSystem | ContextUser | 共享? |
|
||||
|-----------|---------------|-------------|-------|
|
||||
| `useConversationTester` | ✅ | ❌ | ❌ 独立 |
|
||||
| `useConversationOptimization` | ✅ | ❌ | ❌ 独立 |
|
||||
| `usePromptDisplayAdapter` | ✅ | ❌ | ❌ 独立 |
|
||||
| `useTemporaryVariables` | ❌ | ✅ | ❌ 独立 |
|
||||
| `usePromptTester` (App.vue) | ❌ | ✅ (间接) | ❌ 独立 |
|
||||
|
||||
**结论**: ✅ 没有混淆,各自使用专属的 composables
|
||||
|
||||
---
|
||||
|
||||
### 2. 测试逻辑独立性
|
||||
|
||||
**ContextSystemWorkspace**:
|
||||
```typescript
|
||||
// 组件内部
|
||||
const conversationTester = useConversationTester(
|
||||
services || ref(null),
|
||||
selectedTestModel,
|
||||
computed(() => props.optimizationContext),
|
||||
optimizationContextToolsRef,
|
||||
variableManager,
|
||||
selectedMessageId
|
||||
)
|
||||
|
||||
const handleTestWithVariables = async () => {
|
||||
const testVariables = testAreaPanelRef.value?.getVariableValues?.() || {}
|
||||
await conversationTester.executeTest(
|
||||
props.isCompareMode || false,
|
||||
testVariables,
|
||||
testAreaPanelRef.value
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**ContextUserWorkspace**:
|
||||
```typescript
|
||||
// App.vue
|
||||
const promptTester = usePromptTester(
|
||||
services as any,
|
||||
toRef(modelManager, 'selectedTestModel'),
|
||||
selectedOptimizationMode,
|
||||
variableManager
|
||||
)
|
||||
|
||||
const handleTestAreaTest = async (testVariables?: Record<string, string>) => {
|
||||
await promptTester.executeTest(
|
||||
optimizer.prompt,
|
||||
optimizer.optimizedPrompt,
|
||||
testContent.value,
|
||||
isCompareMode.value,
|
||||
testVariables
|
||||
)
|
||||
}
|
||||
|
||||
// ContextUserWorkspace 组件
|
||||
<ContextUserWorkspace
|
||||
@test="handleTestAreaTest"
|
||||
/>
|
||||
```
|
||||
|
||||
**结论**: ✅ 完全独立的测试逻辑
|
||||
- System: 内部管理,会话级测试
|
||||
- User: 外部管理,单消息测试
|
||||
|
||||
---
|
||||
|
||||
### 3. 优化逻辑独立性
|
||||
|
||||
**ContextSystemWorkspace**:
|
||||
```typescript
|
||||
// 消息级优化
|
||||
const conversationOptimization = useConversationOptimization(...)
|
||||
|
||||
const handleOptimizeClick = () => {
|
||||
conversationOptimization.optimizeMessage() // 优化选中消息
|
||||
}
|
||||
```
|
||||
|
||||
**ContextUserWorkspace**:
|
||||
```typescript
|
||||
// 全局优化(通过 App.vue 的 optimizer)
|
||||
<ContextUserWorkspace
|
||||
@optimize="handleOptimizePrompt" // 触发 App.vue 的优化逻辑
|
||||
/>
|
||||
```
|
||||
|
||||
**结论**: ✅ 完全独立的优化逻辑
|
||||
- System: 消息级优化(内部管理)
|
||||
- User: 全局优化(外部管理)
|
||||
|
||||
---
|
||||
|
||||
### 4. 变量管理独立性
|
||||
|
||||
**ContextSystemWorkspace**:
|
||||
- 使用 App.vue 注入的 `variableManager` (useVariableManager)
|
||||
- 通过 inject 获取,用于会话测试
|
||||
|
||||
**ContextUserWorkspace**:
|
||||
- 使用内部的 `tempVarsManager` (useTemporaryVariables)
|
||||
- 独立管理临时变量
|
||||
- 同时使用 App.vue 传入的 globalVariables 和 predefinedVariables
|
||||
|
||||
**结论**: ✅ 独立但合理共享
|
||||
- System: 依赖全局 variableManager(合理)
|
||||
- User: 独立临时变量 + 全局变量(合理)
|
||||
|
||||
---
|
||||
|
||||
### 5. 子组件独立性
|
||||
|
||||
| 子组件 | ContextSystem | ContextUser | 用途差异 |
|
||||
|--------|---------------|-------------|----------|
|
||||
| ConversationManager | ✅ | ❌ | 多消息管理 |
|
||||
| ConversationTestPanel | ✅ | ❌ | 会话测试 |
|
||||
| InputPanelUI | ❌ | ✅ | 单消息输入 |
|
||||
| TestAreaPanel | ❌ | ✅ | 基础测试 |
|
||||
| PromptPanelUI | ✅ | ✅ | **共享**(合理复用) |
|
||||
|
||||
**结论**: ✅ 独立且合理
|
||||
- 共享 PromptPanelUI 是合理的,因为它只是展示组件
|
||||
|
||||
---
|
||||
|
||||
## 🎯 发现的问题
|
||||
|
||||
### ❌ 无问题!架构清晰且独立
|
||||
|
||||
经过全面分析,**没有发现**以下问题:
|
||||
- ❌ 不应该共享但实际共享的 composables
|
||||
- ❌ 逻辑混淆或职责不清
|
||||
- ❌ 组件间的不当耦合
|
||||
- ❌ 数据流混乱
|
||||
|
||||
---
|
||||
|
||||
## ✅ 架构优点
|
||||
|
||||
### 1. 清晰的关注点分离
|
||||
- **ContextSystemWorkspace**: 完全自包含,负责多消息会话优化
|
||||
- **ContextUserWorkspace**: 依赖外部,负责单消息优化
|
||||
|
||||
### 2. Composables 职责清晰
|
||||
|
||||
```
|
||||
useConversationTester → ContextSystemWorkspace 专用
|
||||
useConversationOptimization → ContextSystemWorkspace 专用
|
||||
usePromptDisplayAdapter → ContextSystemWorkspace 专用
|
||||
useTemporaryVariables → ContextUserWorkspace 专用
|
||||
usePromptTester → ContextUserWorkspace 使用(通过 App.vue)
|
||||
```
|
||||
|
||||
### 3. 合理的复用策略
|
||||
- ✅ 展示组件共享(PromptPanelUI)
|
||||
- ✅ 基础工具共享(variableManager)
|
||||
- ✅ 业务逻辑独立(测试器、优化器)
|
||||
|
||||
---
|
||||
|
||||
## 📊 独立性评分
|
||||
|
||||
| 维度 | 评分 | 说明 |
|
||||
|------|------|------|
|
||||
| Composables 独立性 | ⭐⭐⭐⭐⭐ | 完全独立,无混淆 |
|
||||
| 测试逻辑独立性 | ⭐⭐⭐⭐⭐ | 使用不同的测试器 |
|
||||
| 优化逻辑独立性 | ⭐⭐⭐⭐⭐ | 消息级 vs 全局优化 |
|
||||
| 组件职责清晰度 | ⭐⭐⭐⭐⭐ | 职责明确,无重叠 |
|
||||
| 可维护性 | ⭐⭐⭐⭐⭐ | 易于理解和维护 |
|
||||
|
||||
**总评**: ⭐⭐⭐⭐⭐ (5/5)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 建议
|
||||
|
||||
### 无需改进!当前架构已经非常优秀
|
||||
|
||||
两个组件的独立性设计非常好:
|
||||
1. ✅ 各自使用专属的 composables
|
||||
2. ✅ 测试和优化逻辑完全独立
|
||||
3. ✅ 只在合理的地方共享(展示组件)
|
||||
4. ✅ 职责清晰,易于维护
|
||||
|
||||
### 未来扩展建议
|
||||
|
||||
如果要添加新功能,建议遵循当前模式:
|
||||
- **多消息相关**: 添加到 ContextSystemWorkspace 或其专属 composables
|
||||
- **单消息相关**: 添加到 ContextUserWorkspace 或其专属 composables
|
||||
- **共享展示逻辑**: 考虑抽取为独立的展示组件
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
**ContextSystemWorkspace** 和 **ContextUserWorkspace** 两个组件:
|
||||
- ✅ 完全独立,无复用/混淆
|
||||
- ✅ 各自使用专属的业务逻辑 composables
|
||||
- ✅ 只在合理的地方共享展示组件
|
||||
- ✅ 架构清晰,职责明确
|
||||
- ✅ 易于维护和扩展
|
||||
|
||||
**结论**: 当前架构非常优秀,无需改进!🎉
|
||||
@@ -186,7 +186,6 @@
|
||||
@compare-toggle="handleTestAreaCompareToggle"
|
||||
@optimize="handleOptimizePrompt"
|
||||
@iterate="handleIteratePrompt"
|
||||
@test="handleTestAreaTest"
|
||||
@switch-version="handleSwitchVersion"
|
||||
@save-favorite="handleSaveFavorite"
|
||||
@open-global-variables="openVariableManager()"
|
||||
@@ -196,20 +195,10 @@
|
||||
@config-model="modelManager.showConfig = true"
|
||||
@open-input-preview="handleOpenInputPreview"
|
||||
@open-prompt-preview="handleOpenPromptPreview"
|
||||
:selected-message-id="conversationOptimization.selectedMessageId.value"
|
||||
:enable-message-optimization="true"
|
||||
@message-select="handleMessageSelect"
|
||||
:message-optimized-prompt="conversationOptimization.optimizedPrompt.value"
|
||||
:message-versions="conversationOptimization.currentVersions.value"
|
||||
:message-current-version-id="conversationOptimization.currentRecordId.value"
|
||||
:is-message-optimizing="conversationOptimization.isOptimizing.value"
|
||||
:versions="optimizer.currentVersions"
|
||||
:current-version-id="optimizer.currentVersionId"
|
||||
@message-switch-version="handleMessageSwitchVersion"
|
||||
@message-switch-to-v0="handleMessageSwitchToV0"
|
||||
@optimize-message="handleOptimizeMessage"
|
||||
@message-change="handleMessageChange"
|
||||
@message-apply-version="handleApplyMessageVersion"
|
||||
:selected-optimize-model="modelManager.selectedOptimizeModel"
|
||||
:selected-template="currentSelectedTemplate"
|
||||
:selected-test-model="modelManager.selectedTestModel"
|
||||
>
|
||||
<!-- 优化模型选择插槽 -->
|
||||
<template #optimize-model-select>
|
||||
@@ -278,58 +267,17 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 测试结果插槽 -->
|
||||
<template #original-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.originalResult"
|
||||
:reasoning="testResults.originalReasoning"
|
||||
:streaming="testResults.isTestingOriginal"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #optimized-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #single-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
<!-- 🔧 测试结果插槽已移除:ContextSystemWorkspace 内部直接使用 useConversationTester 渲染 -->
|
||||
</ContextSystemWorkspace>
|
||||
|
||||
<!-- 上下文-用户模式 -->
|
||||
<!-- 上下文-用户模式(🆕 已独立,内部管理优化和测试逻辑) -->
|
||||
<ContextUserWorkspace
|
||||
ref="userWorkspaceRef"
|
||||
v-else-if="contextMode === 'user'"
|
||||
:prompt="optimizer.prompt"
|
||||
@update:prompt="optimizer.prompt = $event"
|
||||
:optimized-prompt="optimizer.optimizedPrompt"
|
||||
@update:optimizedPrompt="
|
||||
optimizer.optimizedPrompt = $event
|
||||
"
|
||||
:optimized-reasoning="optimizer.optimizedReasoning"
|
||||
:optimization-mode="selectedOptimizationMode"
|
||||
:is-optimizing="optimizer.isOptimizing"
|
||||
:is-iterating="optimizer.isIterating"
|
||||
:is-test-running="false"
|
||||
:versions="optimizer.currentVersions"
|
||||
:current-version-id="optimizer.currentVersionId"
|
||||
:selected-optimize-model="modelManager.selectedOptimizeModel"
|
||||
:selected-test-model="modelManager.selectedTestModel"
|
||||
:selected-template="selectedTemplate"
|
||||
:selected-iterate-template="
|
||||
optimizer.selectedIterateTemplate
|
||||
"
|
||||
@@ -363,11 +311,7 @@
|
||||
:result-vertical-layout="
|
||||
responsiveLayout.isMobile.value
|
||||
"
|
||||
@optimize="handleOptimizePrompt"
|
||||
@iterate="handleIteratePrompt"
|
||||
@test="handleTestAreaTest"
|
||||
@compare-toggle="handleTestAreaCompareToggle"
|
||||
@switch-version="handleSwitchVersion"
|
||||
@save-favorite="handleSaveFavorite"
|
||||
@open-global-variables="openVariableManager()"
|
||||
@open-tool-manager="
|
||||
@@ -447,39 +391,7 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 测试结果插槽 -->
|
||||
<template #original-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.originalResult"
|
||||
:reasoning="testResults.originalReasoning"
|
||||
:streaming="testResults.isTestingOriginal"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #optimized-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #single-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
<!-- 🔧 测试结果插槽已移除:ContextUserWorkspace 内部直接使用 useContextUserTester 渲染 -->
|
||||
</ContextUserWorkspace>
|
||||
</template>
|
||||
|
||||
@@ -1028,7 +940,6 @@ import {
|
||||
useContextManagement,
|
||||
useAggregatedVariables,
|
||||
useContextEditorUIState,
|
||||
useConversationOptimization,
|
||||
|
||||
// i18n functions
|
||||
initializeI18nWithStorage,
|
||||
@@ -1087,7 +998,7 @@ watch(
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 4. 向子组件提供服务
|
||||
// 4. 向子组件提供服务(部分 provide 移至声明后)
|
||||
provide("services", services);
|
||||
|
||||
// 5. 控制主UI渲染的标志
|
||||
@@ -1331,72 +1242,19 @@ const handleContextEditorStateUpdate =
|
||||
contextManagement.handleContextEditorStateUpdate;
|
||||
const handleContextModeChange = contextManagement.handleContextModeChange;
|
||||
|
||||
// 🆕 多轮对话消息优化管理
|
||||
const selectedOptimizationTemplate = computed<Template | null>(() => {
|
||||
return selectedOptimizationMode.value === "system"
|
||||
? optimizer.selectedOptimizeTemplate
|
||||
: optimizer.selectedUserOptimizeTemplate;
|
||||
});
|
||||
// 🔧 提供依赖给子组件(必须在所有依赖项声明之后)
|
||||
provide("variableManager", variableManager);
|
||||
provide("optimizationContextTools", optimizationContextTools);
|
||||
|
||||
const conversationOptimization = useConversationOptimization(
|
||||
services,
|
||||
optimizationContext,
|
||||
selectedOptimizationMode,
|
||||
toRef(modelManager, "selectedOptimizeModel"),
|
||||
selectedOptimizationTemplate,
|
||||
toRef(optimizer, "selectedIterateTemplate") // 🔧 添加迭代模板
|
||||
);
|
||||
|
||||
provide('conversationOptimization', conversationOptimization);
|
||||
|
||||
// 处理消息选择事件
|
||||
const handleMessageSelect = async (message: ConversationMessage) => {
|
||||
await conversationOptimization.selectMessage(message);
|
||||
};
|
||||
|
||||
// 处理消息版本切换
|
||||
const handleMessageSwitchVersion = async (version: PromptRecordChain['versions'][number]) => {
|
||||
await conversationOptimization.switchVersion(version);
|
||||
};
|
||||
|
||||
// 🆕 处理消息 V0 切换
|
||||
const handleMessageSwitchToV0 = async (version: PromptRecordChain['versions'][number]) => {
|
||||
await conversationOptimization.switchToV0(version);
|
||||
};
|
||||
|
||||
// 处理消息优化
|
||||
const handleOptimizeMessage = async () => {
|
||||
await conversationOptimization.optimizeMessage();
|
||||
};
|
||||
|
||||
// 处理消息变更(用于清理删除消息的映射)
|
||||
const handleMessageChange = (index: number, message: ConversationMessage, action: 'add' | 'update' | 'delete') => {
|
||||
if (!message?.id) return;
|
||||
if (action === 'delete') {
|
||||
conversationOptimization.cleanupDeletedMessageMapping(message.id);
|
||||
} else if (action === 'update') {
|
||||
conversationOptimization.cleanupDeletedMessageMapping(message.id, { keepSelection: true });
|
||||
}
|
||||
};
|
||||
|
||||
// 手动应用所选版本
|
||||
const handleApplyMessageVersion = async () => {
|
||||
await conversationOptimization.applyCurrentVersion();
|
||||
};
|
||||
|
||||
// 🆕 提示词测试管理(支持变量注入、上下文、工具调用)
|
||||
// 🆕 基础模式提示词测试(简化后只用于基础模式和 context-user)
|
||||
const promptTester = usePromptTester(
|
||||
services as any,
|
||||
toRef(modelManager, 'selectedTestModel'),
|
||||
selectedOptimizationMode, // 保持兼容性,后续应改为使用 basicSubMode/proSubMode
|
||||
advancedModeEnabled,
|
||||
optimizationContext,
|
||||
optimizationContextTools,
|
||||
variableManager,
|
||||
conversationOptimization.selectedMessageId // 🆕 传递选中的消息ID用于对比
|
||||
selectedOptimizationMode,
|
||||
variableManager
|
||||
);
|
||||
|
||||
// 测试结果引用(从 promptTester 获取)
|
||||
// 测试结果引用(从 promptTester 获取,用于基础模式和 context-user)
|
||||
const testResults = computed(() => promptTester.testResults);
|
||||
|
||||
// 处理测试面板的变量变化(现在测试变量由TestAreaPanel自己管理,不需要同步到会话)
|
||||
@@ -2276,20 +2134,16 @@ const getActiveTestPanelInstance = (): TestAreaPanelInstance | null => {
|
||||
return null;
|
||||
};
|
||||
|
||||
// 真实测试处理函数
|
||||
// 基础模式和 context-user 模式的测试处理函数
|
||||
// 注意:context-system 模式已在 ContextSystemWorkspace 内部使用 useConversationTester 处理,不会调用此函数
|
||||
const handleTestAreaTest = async (testVariables?: Record<string, string>) => {
|
||||
// 🔧 多轮对话模式(context-system)下,不使用 testContent(测试内容来自会话消息)
|
||||
// 但现在支持对比模式了,可以对比选中消息的 V0 和当前版本
|
||||
const actualTestContent = contextMode.value === 'system' ? '' : testContent.value;
|
||||
|
||||
// 调用 promptTester 的 executeTest 方法
|
||||
// 调用基础测试器(只用于基础模式和 context-user)
|
||||
await promptTester.executeTest(
|
||||
optimizer.prompt,
|
||||
optimizer.optimizedPrompt,
|
||||
actualTestContent,
|
||||
isCompareMode.value, // 🔧 直接使用 isCompareMode,不再强制为 false
|
||||
testVariables,
|
||||
getActiveTestPanelInstance()
|
||||
testContent.value,
|
||||
isCompareMode.value,
|
||||
testVariables
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
:max-height="300"
|
||||
:selected-message-id="selectedMessageId"
|
||||
:enable-message-optimization="enableMessageOptimization"
|
||||
:is-message-optimizing="isMessageOptimizing"
|
||||
@message-select="emit('message-select', $event)"
|
||||
:is-message-optimizing="conversationOptimization.isOptimizing.value"
|
||||
@message-select="conversationOptimization.selectMessage"
|
||||
@optimize-message="handleOptimizeClick"
|
||||
@message-change="(index, message, action) => emit('message-change', index, message, action)"
|
||||
/>
|
||||
@@ -72,12 +72,12 @@
|
||||
<!-- 优化按钮 -->
|
||||
<NButton
|
||||
type="primary"
|
||||
:loading="isOptimizing"
|
||||
:disabled="isOptimizing || !selectedMessageId"
|
||||
:loading="displayAdapter.displayedIsOptimizing.value"
|
||||
:disabled="displayAdapter.displayedIsOptimizing.value || !selectedMessageId"
|
||||
@click="handleOptimizeClick"
|
||||
block
|
||||
>
|
||||
{{ isOptimizing ? $t('common.loading') : $t('promptOptimizer.optimize') }}
|
||||
{{ displayAdapter.displayedIsOptimizing.value ? $t('common.loading') : $t('promptOptimizer.optimize') }}
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
@@ -91,20 +91,20 @@
|
||||
}"
|
||||
content-style="height: 100%; max-height: 100%; overflow: hidden;"
|
||||
>
|
||||
<template v-if="isInMessageOptimizationMode">
|
||||
<template v-if="displayAdapter.isInMessageOptimizationMode.value">
|
||||
<PromptPanelUI
|
||||
:original-prompt="displayedOriginalPrompt"
|
||||
:optimized-prompt="displayedOptimizedPrompt"
|
||||
:original-prompt="displayAdapter.displayedOriginalPrompt.value"
|
||||
:optimized-prompt="displayAdapter.displayedOptimizedPrompt.value"
|
||||
:reasoning="optimizedReasoning"
|
||||
:is-optimizing="displayedIsOptimizing"
|
||||
:is-optimizing="displayAdapter.displayedIsOptimizing.value"
|
||||
:is-iterating="isIterating"
|
||||
:selectedIterateTemplate="selectedIterateTemplate"
|
||||
@update:selectedIterateTemplate="
|
||||
emit('update:selectedIterateTemplate', $event)
|
||||
"
|
||||
:versions="displayedVersions"
|
||||
:current-version-id="displayedCurrentVersionId"
|
||||
:show-apply-button="isInMessageOptimizationMode"
|
||||
:versions="displayAdapter.displayedVersions.value"
|
||||
:current-version-id="displayAdapter.displayedCurrentVersionId.value"
|
||||
:show-apply-button="displayAdapter.isInMessageOptimizationMode.value"
|
||||
:optimization-mode="optimizationMode"
|
||||
:advanced-mode-enabled="true"
|
||||
:show-preview="true"
|
||||
@@ -194,18 +194,39 @@
|
||||
<slot name="test-model-select"></slot>
|
||||
</template>
|
||||
|
||||
<!-- 🆕 对比模式结果插槽 -->
|
||||
<!-- 🆕 对比模式结果插槽:直接绑定测试结果 -->
|
||||
<template #original-result>
|
||||
<slot name="original-result"></slot>
|
||||
<OutputDisplay
|
||||
:content="conversationTester.testResults.originalResult"
|
||||
:reasoning="conversationTester.testResults.originalReasoning"
|
||||
:streaming="conversationTester.testResults.isTestingOriginal"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #optimized-result>
|
||||
<slot name="optimized-result"></slot>
|
||||
<OutputDisplay
|
||||
:content="conversationTester.testResults.optimizedResult"
|
||||
:reasoning="conversationTester.testResults.optimizedReasoning"
|
||||
:streaming="conversationTester.testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 单一结果插槽 -->
|
||||
<template #single-result>
|
||||
<slot name="single-result"></slot>
|
||||
<OutputDisplay
|
||||
:content="conversationTester.testResults.optimizedResult"
|
||||
:reasoning="conversationTester.testResults.optimizedReasoning"
|
||||
:streaming="conversationTester.testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
</ConversationTestPanel>
|
||||
</NCard>
|
||||
@@ -214,7 +235,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, inject } from 'vue'
|
||||
import { ref, computed, inject, provide } from 'vue'
|
||||
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { NCard, NFlex, NButton, NText, NEmpty } from "naive-ui";
|
||||
@@ -222,14 +243,20 @@ import { useBreakpoints } from "@vueuse/core";
|
||||
import PromptPanelUI from "../PromptPanel.vue";
|
||||
import ConversationTestPanel from "./ConversationTestPanel.vue";
|
||||
import ConversationManager from "./ConversationManager.vue";
|
||||
import type { UseConversationOptimization } from '../../composables/prompt/useConversationOptimization'
|
||||
import OutputDisplay from "../OutputDisplay.vue";
|
||||
import { useConversationTester } from '../../composables/prompt/useConversationTester'
|
||||
import { useConversationOptimization } from '../../composables/prompt/useConversationOptimization'
|
||||
import { usePromptDisplayAdapter } from '../../composables/prompt/usePromptDisplayAdapter'
|
||||
import type { OptimizationMode, ConversationMessage } from "../../types";
|
||||
import type {
|
||||
PromptRecord,
|
||||
Template,
|
||||
ToolDefinition,
|
||||
} from "@prompt-optimizer/core";
|
||||
import type { TestAreaPanelInstance } from "../types/test-area";
|
||||
import type { IteratePayload, SaveFavoritePayload } from "../../types/workspace";
|
||||
import type { VariableManagerHooks } from '../../composables/prompt/useVariableManager'
|
||||
import type { AppServices } from '../../types/services'
|
||||
|
||||
// 响应式断点
|
||||
const breakpoints = useBreakpoints({
|
||||
@@ -238,8 +265,7 @@ const breakpoints = useBreakpoints({
|
||||
});
|
||||
const isMobile = breakpoints.smaller("mobile");
|
||||
|
||||
// Props 定义 (移除 contextMode,因为固定为 system;移除 prompt,因为消息输入在 ConversationManager 中)
|
||||
// 🔧 移除 optimizedPrompt/versions/currentVersionId,防止基础模式状态污染
|
||||
// Props 定义
|
||||
interface Props {
|
||||
// 核心状态
|
||||
optimizedReasoning?: string;
|
||||
@@ -250,7 +276,9 @@ interface Props {
|
||||
isIterating: boolean;
|
||||
isTestRunning?: boolean;
|
||||
|
||||
// 版本管理
|
||||
// 外部状态注入(用于初始化本地 hook)
|
||||
selectedOptimizeModel: string;
|
||||
selectedTemplate: Template | null;
|
||||
selectedIterateTemplate: Template | null;
|
||||
|
||||
// 上下文数据 (系统模式专属)
|
||||
@@ -263,14 +291,9 @@ interface Props {
|
||||
availableVariables: Record<string, string>;
|
||||
scanVariables: (content: string) => string[];
|
||||
|
||||
// 🆕 消息优化功能
|
||||
selectedMessageId?: string;
|
||||
// 🆕 消息优化功能(本地管理,移除部分外部 props)
|
||||
enableMessageOptimization?: boolean;
|
||||
messageOptimizedPrompt?: string;
|
||||
messageVersions?: PromptRecord[];
|
||||
messageCurrentVersionId?: string | null;
|
||||
isMessageOptimizing?: boolean;
|
||||
|
||||
|
||||
// 全局优化链(用于历史记录恢复)
|
||||
versions?: PromptRecord[];
|
||||
currentVersionId?: string;
|
||||
@@ -284,6 +307,9 @@ interface Props {
|
||||
|
||||
// 🆕 对比模式
|
||||
isCompareMode?: boolean;
|
||||
|
||||
// 🆕 测试相关(避免通过 App.vue 中转)
|
||||
selectedTestModel?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -294,28 +320,20 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
buttonSize: "medium",
|
||||
conversationMaxHeight: 300,
|
||||
resultVerticalLayout: false,
|
||||
selectedMessageId: undefined,
|
||||
enableMessageOptimization: false,
|
||||
messageOptimizedPrompt: "",
|
||||
messageVersions: () => [],
|
||||
messageCurrentVersionId: null,
|
||||
isMessageOptimizing: false,
|
||||
isCompareMode: false,
|
||||
});
|
||||
|
||||
// Emits 定义
|
||||
// 🔧 移除 update:optimizedPrompt,防止基础模式状态污染
|
||||
const emit = defineEmits<{
|
||||
// 数据更新
|
||||
"update:selectedIterateTemplate": [value: Template | null];
|
||||
"update:optimizationContext": [value: ConversationMessage[]];
|
||||
|
||||
// 操作事件
|
||||
optimize: []; // 执行优化
|
||||
iterate: [payload: IteratePayload];
|
||||
test: [testVariables: Record<string, string>]; // 🆕 传递测试变量
|
||||
// 操作事件(用于历史记录查看场景)
|
||||
test: [testVariables: Record<string, string>];
|
||||
"switch-version": [version: PromptRecord];
|
||||
"switch-to-v0": [version: PromptRecord]; // 🆕 V0 切换事件
|
||||
"switch-to-v0": [version: PromptRecord];
|
||||
"save-favorite": [data: SaveFavoritePayload];
|
||||
|
||||
// 打开面板/管理器
|
||||
@@ -332,14 +350,6 @@ const emit = defineEmits<{
|
||||
"variable-change": [name: string, value: string];
|
||||
"save-to-global": [name: string, value: string];
|
||||
|
||||
// 🆕 消息优化相关
|
||||
"message-select": [message: ConversationMessage];
|
||||
"message-switch-version": [version: PromptRecord];
|
||||
"message-switch-to-v0": [version: PromptRecord]; // 🆕 消息 V0 切换事件
|
||||
"optimize-message": [];
|
||||
"message-change": [index: number, message: ConversationMessage, action: 'add' | 'update' | 'delete'];
|
||||
"message-apply-version": [];
|
||||
|
||||
// 🆕 对比模式
|
||||
"update:isCompareMode": [value: boolean];
|
||||
"compare-toggle": [];
|
||||
@@ -347,110 +357,100 @@ const emit = defineEmits<{
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const conversationOptimization = inject<UseConversationOptimization>('conversationOptimization')
|
||||
// 注入服务和变量管理器
|
||||
const services = inject<Ref<AppServices | null>>('services')
|
||||
const variableManager = inject<VariableManagerHooks | null>('variableManager')
|
||||
|
||||
// 🆕 初始化本地会话优化逻辑
|
||||
const conversationOptimization = useConversationOptimization(
|
||||
services || ref(null),
|
||||
computed(() => props.optimizationContext),
|
||||
computed(() => props.optimizationMode),
|
||||
computed(() => props.selectedOptimizeModel),
|
||||
computed(() => props.selectedTemplate),
|
||||
computed(() => props.selectedIterateTemplate)
|
||||
)
|
||||
|
||||
// 暴露给子组件(虽然目前主要通过 Props 传递给 ConversationManager,但保持 Provide 以防万一)
|
||||
provide('conversationOptimization', conversationOptimization);
|
||||
|
||||
// 🆕 初始化显示适配器(根据模式自动切换数据源)
|
||||
const displayAdapter = usePromptDisplayAdapter(
|
||||
conversationOptimization,
|
||||
{
|
||||
enableMessageOptimization: computed(() => props.enableMessageOptimization || false),
|
||||
optimizationContext: computed(() => props.optimizationContext),
|
||||
globalVersions: computed(() => props.versions || []),
|
||||
globalCurrentVersionId: computed(() => props.currentVersionId),
|
||||
globalIsOptimizing: computed(() => props.isOptimizing),
|
||||
}
|
||||
)
|
||||
|
||||
// 🆕 初始化多对话测试器
|
||||
const selectedTestModel = computed(() => props.selectedTestModel || '')
|
||||
// 从 inject 获取 optimizationContextTools(由 App.vue 提供)
|
||||
const optimizationContextToolsRef = inject<Ref<ToolDefinition[]>>('optimizationContextTools', ref([]))
|
||||
// 使用本地 managed 的 selectedMessageId
|
||||
const selectedMessageId = conversationOptimization.selectedMessageId
|
||||
|
||||
const conversationTester = useConversationTester(
|
||||
services || ref(null),
|
||||
selectedTestModel,
|
||||
computed(() => props.optimizationContext),
|
||||
optimizationContextToolsRef,
|
||||
variableManager,
|
||||
selectedMessageId
|
||||
)
|
||||
|
||||
// 处理迭代优化事件
|
||||
// 注意:由于 displayedOptimizedPrompt 在未选中消息时为空,迭代按钮不会显示,所以此函数调用时必定处于消息优化模式
|
||||
const handleIterate = (payload: IteratePayload) => {
|
||||
if (isInMessageOptimizationMode.value && conversationOptimization) {
|
||||
conversationOptimization.iterateMessage(payload)
|
||||
} else {
|
||||
emit('iterate', payload)
|
||||
}
|
||||
conversationOptimization.iterateMessage(payload)
|
||||
}
|
||||
|
||||
// 处理优化点击事件
|
||||
// 注意:优化按钮在没有选中消息时会被禁用,所以此函数调用时必定处于消息优化模式
|
||||
const handleOptimizeClick = () => {
|
||||
if (isInMessageOptimizationMode.value && conversationOptimization) {
|
||||
conversationOptimization.optimizeMessage()
|
||||
} else {
|
||||
emit('optimize-message')
|
||||
}
|
||||
conversationOptimization.optimizeMessage()
|
||||
}
|
||||
|
||||
// 🆕 ConversationTestPanel 引用(兼容 TestAreaPanelInstance 接口)
|
||||
// 🆕 ConversationTestPanel 引用
|
||||
const testAreaPanelRef = ref<TestAreaPanelInstance | null>(null);
|
||||
|
||||
// 🆕 消息优化模式:根据是否有选中消息来决定显示内容
|
||||
const isInMessageOptimizationMode = computed(() => {
|
||||
return props.enableMessageOptimization && !!props.selectedMessageId;
|
||||
});
|
||||
|
||||
// 🆕 PromptPanel 显示的原始提示词(当前选中消息的原始内容)
|
||||
const displayedOriginalPrompt = computed(() => {
|
||||
if (!isInMessageOptimizationMode.value) return ''
|
||||
const message = props.optimizationContext?.find(m => m.id === props.selectedMessageId)
|
||||
return message?.originalContent || message?.content || ''
|
||||
});
|
||||
|
||||
// 🆕 PromptPanel 显示的优化结果(消息优化 或 提示词优化)
|
||||
const displayedOptimizedPrompt = computed(() => {
|
||||
return isInMessageOptimizationMode.value
|
||||
? props.messageOptimizedPrompt
|
||||
: ''; // 没有选中消息时,不显示优化结果
|
||||
});
|
||||
|
||||
// 🆕 PromptPanel 显示的版本列表
|
||||
const displayedVersions = computed(() => {
|
||||
if (isInMessageOptimizationMode.value) {
|
||||
// 消息优化模式:使用消息级优化版本
|
||||
return props.messageVersions || [];
|
||||
}
|
||||
// 历史记录恢复时:使用全局优化链
|
||||
return props.versions || [];
|
||||
});
|
||||
|
||||
// 🆕 PromptPanel 显示的当前版本ID
|
||||
const displayedCurrentVersionId = computed(() => {
|
||||
if (isInMessageOptimizationMode.value) {
|
||||
// 消息优化模式:使用消息级版本ID
|
||||
return props.messageCurrentVersionId || null;
|
||||
}
|
||||
// 历史记录恢复时:使用全局版本ID
|
||||
return props.currentVersionId || null;
|
||||
});
|
||||
|
||||
// 🆕 PromptPanel 显示的优化中状态
|
||||
const displayedIsOptimizing = computed(() => {
|
||||
return isInMessageOptimizationMode.value
|
||||
? props.isMessageOptimizing
|
||||
: props.isOptimizing;
|
||||
});
|
||||
|
||||
// 🆕 处理版本切换:根据模式决定触发哪个事件
|
||||
// 🆕 处理版本切换
|
||||
const handleSwitchVersion = (version: PromptRecord) => {
|
||||
if (isInMessageOptimizationMode.value) {
|
||||
// 消息优化模式:触发消息版本切换事件
|
||||
emit('message-switch-version', version);
|
||||
if (displayAdapter.isInMessageOptimizationMode.value) {
|
||||
conversationOptimization.switchVersion(version);
|
||||
} else {
|
||||
// 提示词优化模式:触发普通版本切换事件
|
||||
emit('switch-version', version);
|
||||
}
|
||||
};
|
||||
|
||||
// 🆕 处理 V0 切换:根据模式决定触发哪个事件
|
||||
// 🆕 处理 V0 切换
|
||||
const handleSwitchToV0 = (version: PromptRecord) => {
|
||||
if (isInMessageOptimizationMode.value) {
|
||||
// 消息优化模式:触发消息 V0 切换事件
|
||||
emit('message-switch-to-v0', version);
|
||||
if (displayAdapter.isInMessageOptimizationMode.value) {
|
||||
conversationOptimization.switchToV0(version);
|
||||
} else {
|
||||
// 提示词优化模式:触发普通 V0 切换事件
|
||||
emit('switch-to-v0', version);
|
||||
}
|
||||
};
|
||||
|
||||
const handleApplyToConversation = () => {
|
||||
if (!isInMessageOptimizationMode.value) return;
|
||||
emit('message-apply-version');
|
||||
if (!displayAdapter.isInMessageOptimizationMode.value) return;
|
||||
conversationOptimization.applyCurrentVersion();
|
||||
};
|
||||
|
||||
// 🆕 处理测试事件并获取测试变量
|
||||
// 🆕 处理测试事件
|
||||
const handleTestWithVariables = async () => {
|
||||
// 从 ref 获取测试变量
|
||||
const testVariables = testAreaPanelRef.value?.getVariableValues?.() || {};
|
||||
|
||||
// 触发测试事件,传递测试变量给 App.vue
|
||||
emit('test', testVariables);
|
||||
await conversationTester.executeTest(
|
||||
props.isCompareMode || false,
|
||||
testVariables,
|
||||
testAreaPanelRef.value
|
||||
);
|
||||
};
|
||||
|
||||
// 暴露 TestAreaPanel 引用给父组件(用于工具调用等高级功能)
|
||||
// 暴露引用
|
||||
defineExpose({
|
||||
testAreaPanelRef
|
||||
});
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
<!-- 提示词输入面板 -->
|
||||
<NCard style="flex-shrink: 0; min-height: 200px">
|
||||
<InputPanelUI
|
||||
:modelValue="prompt"
|
||||
@update:modelValue="emit('update:prompt', $event)"
|
||||
v-model="contextUserOptimization.prompt"
|
||||
:label="t('promptOptimizer.userPromptInput')"
|
||||
:placeholder="t('promptOptimizer.userPromptPlaceholder')"
|
||||
:help-text="variableGuideInlineHint"
|
||||
@@ -35,10 +34,10 @@
|
||||
:template-label="t('promptOptimizer.templateLabel')"
|
||||
:button-text="t('promptOptimizer.optimize')"
|
||||
:loading-text="t('common.loading')"
|
||||
:loading="isOptimizing"
|
||||
:disabled="isOptimizing"
|
||||
:loading="contextUserOptimization.isOptimizing"
|
||||
:disabled="contextUserOptimization.isOptimizing"
|
||||
:show-preview="true"
|
||||
@submit="emit('optimize')"
|
||||
@submit="handleOptimize"
|
||||
@configModel="emit('config-model')"
|
||||
@open-preview="emit('open-input-preview')"
|
||||
:enable-variable-extraction="true"
|
||||
@@ -81,26 +80,24 @@
|
||||
content-style="height: 100%; max-height: 100%; overflow: hidden;"
|
||||
>
|
||||
<PromptPanelUI
|
||||
:optimized-prompt="optimizedPrompt"
|
||||
@update:optimizedPrompt="
|
||||
emit('update:optimizedPrompt', $event)
|
||||
"
|
||||
:reasoning="optimizedReasoning"
|
||||
:original-prompt="prompt"
|
||||
:is-optimizing="isOptimizing"
|
||||
:is-iterating="isIterating"
|
||||
:optimized-prompt="contextUserOptimization.optimizedPrompt"
|
||||
@update:optimizedPrompt="contextUserOptimization.optimizedPrompt = $event"
|
||||
:reasoning="contextUserOptimization.optimizedReasoning"
|
||||
:original-prompt="contextUserOptimization.prompt"
|
||||
:is-optimizing="contextUserOptimization.isOptimizing"
|
||||
:is-iterating="contextUserOptimization.isIterating"
|
||||
:selectedIterateTemplate="selectedIterateTemplate"
|
||||
@update:selectedIterateTemplate="
|
||||
emit('update:selectedIterateTemplate', $event)
|
||||
"
|
||||
:versions="versions"
|
||||
:current-version-id="currentVersionId"
|
||||
:versions="contextUserOptimization.currentVersions"
|
||||
:current-version-id="contextUserOptimization.currentVersionId"
|
||||
:optimization-mode="optimizationMode"
|
||||
:advanced-mode-enabled="true"
|
||||
:show-preview="true"
|
||||
@iterate="emit('iterate', $event)"
|
||||
@iterate="handleIterate"
|
||||
@openTemplateManager="emit('open-template-manager', $event)"
|
||||
@switchVersion="emit('switch-version', $event)"
|
||||
@switchVersion="handleSwitchVersion"
|
||||
@save-favorite="emit('save-favorite', $event)"
|
||||
@open-preview="emit('open-prompt-preview')"
|
||||
/>
|
||||
@@ -159,8 +156,8 @@
|
||||
ref="testAreaPanelRef"
|
||||
:optimization-mode="optimizationMode"
|
||||
context-mode="user"
|
||||
:optimized-prompt="optimizedPrompt"
|
||||
:is-test-running="isTestRunning"
|
||||
:optimized-prompt="contextUserOptimization.optimizedPrompt"
|
||||
:is-test-running="contextUserTester.testResults.isTestingOriginal || contextUserTester.testResults.isTestingOptimized"
|
||||
:global-variables="globalVariables"
|
||||
:predefined-variables="predefinedVariables"
|
||||
:temporary-variables="temporaryVariables"
|
||||
@@ -192,17 +189,39 @@
|
||||
<slot name="test-model-select"></slot>
|
||||
</template>
|
||||
|
||||
<!-- 结果显示插槽 -->
|
||||
<!-- 🆕 对比模式结果插槽:直接绑定测试结果 -->
|
||||
<template #original-result>
|
||||
<slot name="original-result"></slot>
|
||||
<OutputDisplay
|
||||
:content="contextUserTester.testResults.originalResult"
|
||||
:reasoning="contextUserTester.testResults.originalReasoning"
|
||||
:streaming="contextUserTester.testResults.isTestingOriginal"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #optimized-result>
|
||||
<slot name="optimized-result"></slot>
|
||||
<OutputDisplay
|
||||
:content="contextUserTester.testResults.optimizedResult"
|
||||
:reasoning="contextUserTester.testResults.optimizedReasoning"
|
||||
:streaming="contextUserTester.testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 单一结果插槽 -->
|
||||
<template #single-result>
|
||||
<slot name="single-result"></slot>
|
||||
<OutputDisplay
|
||||
:content="contextUserTester.testResults.optimizedResult"
|
||||
:reasoning="contextUserTester.testResults.optimizedReasoning"
|
||||
:streaming="contextUserTester.testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
</TestAreaPanel>
|
||||
</NCard>
|
||||
@@ -220,6 +239,7 @@
|
||||
* - 右侧: 测试区域 (变量输入 + 测试执行)
|
||||
*
|
||||
* @features
|
||||
* - 🆕 完全独立的优化和测试逻辑(使用专属 composables)
|
||||
* - 支持提示词优化和迭代
|
||||
* - 支持版本管理和历史记录
|
||||
* - 支持变量系统 (全局变量 + 测试临时变量)
|
||||
@@ -231,16 +251,14 @@
|
||||
* @example
|
||||
* ```vue
|
||||
* <ContextUserWorkspace
|
||||
* v-model:prompt="userPrompt"
|
||||
* v-model:optimizedPrompt="optimizedResult"
|
||||
* :is-optimizing="loading"
|
||||
* :optimization-mode="optimizationMode"
|
||||
* :selected-optimize-model="modelKey"
|
||||
* :selected-template="template"
|
||||
* :global-variables="globalVars"
|
||||
* @optimize="handleOptimize"
|
||||
* @test="handleTest"
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, inject, type Ref } from 'vue'
|
||||
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { NCard, NFlex, NButton, NText } from "naive-ui";
|
||||
@@ -248,6 +266,7 @@ import { useBreakpoints } from "@vueuse/core";
|
||||
import InputPanelUI from "../InputPanel.vue";
|
||||
import PromptPanelUI from "../PromptPanel.vue";
|
||||
import TestAreaPanel from "../TestAreaPanel.vue";
|
||||
import OutputDisplay from "../OutputDisplay.vue";
|
||||
import type { OptimizationMode } from "../../types";
|
||||
import type {
|
||||
PromptRecord,
|
||||
@@ -255,7 +274,11 @@ import type {
|
||||
} from "@prompt-optimizer/core";
|
||||
import type { TestAreaPanelInstance } from "../types/test-area";
|
||||
import type { IteratePayload, SaveFavoritePayload } from "../../types/workspace";
|
||||
import type { AppServices } from '../../types/services';
|
||||
import type { VariableManagerHooks } from '../../composables/prompt/useVariableManager';
|
||||
import { useTemporaryVariables } from "../../composables/variable/useTemporaryVariables";
|
||||
import { useContextUserOptimization } from '../../composables/prompt/useContextUserOptimization';
|
||||
import { useContextUserTester } from '../../composables/prompt/useContextUserTester';
|
||||
|
||||
// ========================
|
||||
// 响应式断点配置
|
||||
@@ -271,28 +294,16 @@ const isMobile = breakpoints.smaller("mobile");
|
||||
// ========================
|
||||
interface Props {
|
||||
// --- 核心状态 ---
|
||||
/** 用户输入的原始提示词 */
|
||||
prompt: string;
|
||||
/** AI 优化后的提示词 */
|
||||
optimizedPrompt: string;
|
||||
/** 优化推理过程说明 (可选) */
|
||||
optimizedReasoning?: string;
|
||||
/** 优化模式 */
|
||||
optimizationMode: OptimizationMode;
|
||||
|
||||
// --- 优化状态 ---
|
||||
/** 是否正在优化 */
|
||||
isOptimizing: boolean;
|
||||
/** 是否正在迭代优化 */
|
||||
isIterating: boolean;
|
||||
/** 是否正在执行测试 */
|
||||
isTestRunning?: boolean;
|
||||
|
||||
// --- 版本管理 ---
|
||||
/** 历史版本列表 */
|
||||
versions: PromptRecord[];
|
||||
/** 当前版本 ID */
|
||||
currentVersionId: string | null;
|
||||
// --- 🆕 模型和模板配置(用于初始化 composables)---
|
||||
/** 优化模型 */
|
||||
selectedOptimizeModel: string;
|
||||
/** 测试模型 */
|
||||
selectedTestModel: string;
|
||||
/** 优化模板 */
|
||||
selectedTemplate: Template | null;
|
||||
/** 选中的迭代模板 */
|
||||
selectedIterateTemplate: Template | null;
|
||||
|
||||
@@ -301,6 +312,8 @@ interface Props {
|
||||
testContent: string;
|
||||
/** 是否启用对比模式 */
|
||||
isCompareMode: boolean;
|
||||
/** 是否正在执行测试(兼容性保留,实际由内部管理)*/
|
||||
isTestRunning?: boolean;
|
||||
|
||||
// --- 变量数据 ---
|
||||
/** 全局变量 (持久化存储) */
|
||||
@@ -322,7 +335,6 @@ interface Props {
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
optimizedReasoning: "",
|
||||
isTestRunning: false,
|
||||
inputMode: "normal",
|
||||
controlBarLayout: "default",
|
||||
@@ -336,23 +348,13 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
// ========================
|
||||
const emit = defineEmits<{
|
||||
// --- 数据更新事件 ---
|
||||
"update:prompt": [value: string];
|
||||
"update:optimizedPrompt": [value: string];
|
||||
"update:selectedIterateTemplate": [value: Template | null];
|
||||
"update:testContent": [value: string];
|
||||
"update:isCompareMode": [value: boolean];
|
||||
|
||||
// --- 操作事件 ---
|
||||
/** 执行优化 */
|
||||
optimize: [];
|
||||
/** 执行迭代优化 */
|
||||
iterate: [payload: IteratePayload];
|
||||
/** 执行测试 (传递测试变量) */
|
||||
test: [testVariables: Record<string, string>];
|
||||
/** 切换对比模式 */
|
||||
"compare-toggle": [];
|
||||
/** 切换历史版本 */
|
||||
"switch-version": [version: PromptRecord];
|
||||
/** 保存到收藏 */
|
||||
"save-favorite": [data: SaveFavoritePayload];
|
||||
|
||||
@@ -373,7 +375,6 @@ const emit = defineEmits<{
|
||||
"open-input-preview": [];
|
||||
/** 打开提示词预览 */
|
||||
"open-prompt-preview": [];
|
||||
/** 打开测试预览 */
|
||||
|
||||
// --- 变量管理 ---
|
||||
/** 变量值变化 */
|
||||
@@ -392,6 +393,12 @@ const emit = defineEmits<{
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// ========================
|
||||
// 注入服务和变量管理器
|
||||
// ========================
|
||||
const services = inject<Ref<AppServices | null>>('services');
|
||||
const variableManager = inject<VariableManagerHooks | null>('variableManager');
|
||||
|
||||
// ========================
|
||||
// 内部状态管理
|
||||
// ========================
|
||||
@@ -399,6 +406,21 @@ const { t } = useI18n();
|
||||
const tempVarsManager = useTemporaryVariables();
|
||||
const temporaryVariables = tempVarsManager.temporaryVariables;
|
||||
|
||||
// 🆕 初始化 ContextUser 专属优化器
|
||||
const contextUserOptimization = useContextUserOptimization(
|
||||
services || ref(null),
|
||||
computed(() => props.selectedOptimizeModel),
|
||||
computed(() => props.selectedTemplate),
|
||||
computed(() => props.selectedIterateTemplate)
|
||||
);
|
||||
|
||||
// 🆕 初始化 ContextUser 专属测试器
|
||||
const contextUserTester = useContextUserTester(
|
||||
services || ref(null),
|
||||
computed(() => props.selectedTestModel),
|
||||
variableManager
|
||||
);
|
||||
|
||||
// ========================
|
||||
// 计算属性
|
||||
// ========================
|
||||
@@ -530,14 +552,37 @@ const handleClearTemporaryVariables = () => {
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理测试事件并获取测试变量
|
||||
* 🆕 处理优化事件
|
||||
*/
|
||||
const handleOptimize = () => {
|
||||
contextUserOptimization.optimize();
|
||||
};
|
||||
|
||||
/**
|
||||
* 🆕 处理迭代优化事件
|
||||
*/
|
||||
const handleIterate = (payload: IteratePayload) => {
|
||||
contextUserOptimization.iterate({
|
||||
originalPrompt: contextUserOptimization.prompt,
|
||||
optimizedPrompt: contextUserOptimization.optimizedPrompt,
|
||||
iterateInput: payload.iterationNote
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 🆕 处理版本切换事件
|
||||
*/
|
||||
const handleSwitchVersion = (version: PromptRecord) => {
|
||||
contextUserOptimization.switchVersion(version);
|
||||
};
|
||||
|
||||
/**
|
||||
* 🆕 处理测试事件(使用内部测试器)
|
||||
*
|
||||
* 工作流程:
|
||||
* 1. 从 TestAreaPanel 获取用户输入的测试变量
|
||||
* 2. 验证数据有效性
|
||||
* 3. 触发 test 事件,传递变量给父组件
|
||||
*
|
||||
* @emits test 传递测试变量给父组件执行测试
|
||||
* 3. 调用内部测试器执行测试
|
||||
*/
|
||||
const handleTestWithVariables = async () => {
|
||||
try {
|
||||
@@ -546,7 +591,6 @@ const handleTestWithVariables = async () => {
|
||||
console.warn(
|
||||
"[ContextUserWorkspace] testAreaPanelRef not available, using empty variables",
|
||||
);
|
||||
emit("test", {});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -556,7 +600,6 @@ const handleTestWithVariables = async () => {
|
||||
console.warn(
|
||||
"[ContextUserWorkspace] getVariableValues method not found, using empty variables",
|
||||
);
|
||||
emit("test", {});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -569,20 +612,23 @@ const handleTestWithVariables = async () => {
|
||||
typeof testVariables,
|
||||
);
|
||||
window.$message?.error(t("test.invalidVariables"));
|
||||
emit("test", {});
|
||||
return;
|
||||
}
|
||||
|
||||
// 触发测试事件,传递变量
|
||||
emit("test", testVariables);
|
||||
// 🆕 调用内部测试器执行测试
|
||||
await contextUserTester.executeTest(
|
||||
contextUserOptimization.prompt,
|
||||
contextUserOptimization.optimizedPrompt,
|
||||
props.testContent,
|
||||
props.isCompareMode,
|
||||
testVariables
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[ContextUserWorkspace] Failed to get test variables:",
|
||||
"[ContextUserWorkspace] Failed to execute test:",
|
||||
error,
|
||||
);
|
||||
window.$message?.error(t("test.getVariablesFailed"));
|
||||
// 即使出错也触发测试,使用空变量
|
||||
emit("test", {});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
// 提示词相关 composables
|
||||
export * from './usePromptOptimizer'
|
||||
export * from './usePromptTester'
|
||||
export * from './useConversationTester' // 🆕 多对话测试
|
||||
export * from './usePromptHistory'
|
||||
export * from './usePromptPreview'
|
||||
export * from './useTemplateManager'
|
||||
export * from './useVariableManager'
|
||||
export * from './useConversationOptimization'
|
||||
export * from './useContextUserOptimization' // 🆕 ContextUser 优化器
|
||||
export * from './useContextUserTester' // 🆕 ContextUser 测试器
|
||||
export * from './usePromptDisplayAdapter' // 🆕 提示词显示适配器
|
||||
|
||||
// 变量管理相关 composables
|
||||
export * from '../variable'
|
||||
|
||||
288
packages/ui/src/composables/prompt/useContextUserOptimization.ts
Normal file
288
packages/ui/src/composables/prompt/useContextUserOptimization.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import { ref, nextTick, computed, reactive, type Ref } from 'vue'
|
||||
import { useToast } from '../ui/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getErrorMessage } from '../../utils/error'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import type {
|
||||
Template,
|
||||
PromptRecordChain,
|
||||
OptimizationRequest,
|
||||
ToolDefinition
|
||||
} from '@prompt-optimizer/core'
|
||||
import type { AppServices } from '../../types/services'
|
||||
|
||||
type PromptChain = PromptRecordChain
|
||||
|
||||
/**
|
||||
* ContextUser 模式提示词优化器接口
|
||||
*/
|
||||
export interface UseContextUserOptimization {
|
||||
// 状态
|
||||
prompt: string
|
||||
optimizedPrompt: string
|
||||
optimizedReasoning: string
|
||||
isOptimizing: boolean
|
||||
isIterating: boolean
|
||||
selectedTemplate: Template | null
|
||||
selectedIterateTemplate: Template | null
|
||||
currentChainId: string
|
||||
currentVersions: PromptChain['versions']
|
||||
currentVersionId: string
|
||||
|
||||
// 方法
|
||||
optimize: () => Promise<void>
|
||||
iterate: (payload: { originalPrompt: string, optimizedPrompt: string, iterateInput: string }) => Promise<void>
|
||||
switchVersion: (version: PromptChain['versions'][number]) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* ContextUser 模式提示词优化器 Composable
|
||||
*
|
||||
* 专门用于 ContextUserWorkspace 的优化逻辑,特点:
|
||||
* - 只处理单条用户消息优化
|
||||
* - 独立的状态管理
|
||||
* - 支持版本历史和迭代
|
||||
* - 与 ContextSystem 的 useConversationOptimization 对称
|
||||
*
|
||||
* @param services 服务实例引用
|
||||
* @param selectedOptimizeModel 优化模型选择
|
||||
* @param selectedTemplate 优化模板(用户模式)
|
||||
* @param selectedIterateTemplate 迭代模板
|
||||
* @returns ContextUser 优化器接口
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const contextUserOptimization = useContextUserOptimization(
|
||||
* services,
|
||||
* computed(() => props.selectedOptimizeModel),
|
||||
* computed(() => props.selectedTemplate),
|
||||
* computed(() => props.selectedIterateTemplate)
|
||||
* )
|
||||
*
|
||||
* // 执行优化
|
||||
* await contextUserOptimization.optimize()
|
||||
* ```
|
||||
*/
|
||||
export function useContextUserOptimization(
|
||||
services: Ref<AppServices | null>,
|
||||
selectedOptimizeModel: Ref<string>,
|
||||
selectedTemplate: Ref<Template | null>,
|
||||
selectedIterateTemplate: Ref<Template | null>
|
||||
): UseContextUserOptimization {
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 服务引用
|
||||
const historyManager = computed(() => services.value?.historyManager)
|
||||
const promptService = computed(() => services.value?.promptService)
|
||||
|
||||
// 使用 reactive 创建响应式状态对象
|
||||
const state = reactive<UseContextUserOptimization>({
|
||||
// 状态
|
||||
prompt: '',
|
||||
optimizedPrompt: '',
|
||||
optimizedReasoning: '',
|
||||
isOptimizing: false,
|
||||
isIterating: false,
|
||||
selectedTemplate: null,
|
||||
selectedIterateTemplate: null,
|
||||
currentChainId: '',
|
||||
currentVersions: [],
|
||||
currentVersionId: '',
|
||||
|
||||
// 方法
|
||||
optimize: async () => {
|
||||
if (!state.prompt.trim() || state.isOptimizing) return
|
||||
|
||||
if (!selectedTemplate.value) {
|
||||
toast.error(t('toast.error.noOptimizeTemplate'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedOptimizeModel.value) {
|
||||
toast.error(t('toast.error.noOptimizeModel'))
|
||||
return
|
||||
}
|
||||
|
||||
// 在开始优化前立即清空状态
|
||||
state.isOptimizing = true
|
||||
state.optimizedPrompt = ''
|
||||
state.optimizedReasoning = ''
|
||||
|
||||
// 等待一个微任务确保状态更新完成
|
||||
await nextTick()
|
||||
|
||||
try {
|
||||
// 构建优化请求
|
||||
const request: OptimizationRequest = {
|
||||
optimizationMode: 'user', // ContextUser 固定为 user 模式
|
||||
targetPrompt: state.prompt,
|
||||
templateId: selectedTemplate.value.id,
|
||||
modelKey: selectedOptimizeModel.value
|
||||
}
|
||||
|
||||
// 使用流式优化 API
|
||||
await promptService.value!.optimizePromptStream(
|
||||
request,
|
||||
{
|
||||
onToken: (token: string) => {
|
||||
state.optimizedPrompt += token
|
||||
},
|
||||
onReasoningToken: (reasoningToken: string) => {
|
||||
state.optimizedReasoning += reasoningToken
|
||||
},
|
||||
onComplete: async () => {
|
||||
if (!selectedTemplate.value) return
|
||||
|
||||
try {
|
||||
// 创建历史记录
|
||||
const recordData = {
|
||||
id: uuidv4(),
|
||||
originalPrompt: state.prompt,
|
||||
optimizedPrompt: state.optimizedPrompt,
|
||||
type: 'contextUserOptimize' as const, // ContextUser 专用类型
|
||||
modelKey: selectedOptimizeModel.value,
|
||||
templateId: selectedTemplate.value.id,
|
||||
timestamp: Date.now(),
|
||||
metadata: {
|
||||
optimizationMode: 'user' as const,
|
||||
functionMode: 'pro' as const // ContextUser 属于 pro 模式
|
||||
}
|
||||
}
|
||||
|
||||
const newRecord = await historyManager.value!.createNewChain(recordData)
|
||||
|
||||
state.currentChainId = newRecord.chainId
|
||||
state.currentVersions = newRecord.versions
|
||||
state.currentVersionId = newRecord.currentRecord.id
|
||||
|
||||
toast.success(t('toast.success.optimizeSuccess'))
|
||||
} catch (error: unknown) {
|
||||
console.error('创建历史记录失败:', error)
|
||||
toast.error('创建历史记录失败: ' + getErrorMessage(error))
|
||||
} finally {
|
||||
state.isOptimizing = false
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
console.error(t('toast.error.optimizeProcessFailed'), error)
|
||||
toast.error(error.message || t('toast.error.optimizeFailed'))
|
||||
state.isOptimizing = false
|
||||
}
|
||||
}
|
||||
)
|
||||
} catch (error: unknown) {
|
||||
console.error(t('toast.error.optimizeFailed'), error)
|
||||
toast.error(getErrorMessage(error) || t('toast.error.optimizeFailed'))
|
||||
} finally {
|
||||
state.isOptimizing = false
|
||||
}
|
||||
},
|
||||
|
||||
// 迭代优化
|
||||
iterate: async ({ originalPrompt, optimizedPrompt: lastOptimizedPrompt, iterateInput }) => {
|
||||
if (!originalPrompt || !lastOptimizedPrompt || !iterateInput || state.isIterating) return
|
||||
|
||||
if (!selectedIterateTemplate.value) {
|
||||
toast.error(t('toast.error.noIterateTemplate'))
|
||||
return
|
||||
}
|
||||
|
||||
// 在开始迭代前立即清空状态
|
||||
state.isIterating = true
|
||||
state.optimizedPrompt = ''
|
||||
state.optimizedReasoning = ''
|
||||
|
||||
// 等待一个微任务确保状态更新完成
|
||||
await nextTick()
|
||||
|
||||
try {
|
||||
await promptService.value!.iteratePromptStream(
|
||||
originalPrompt,
|
||||
lastOptimizedPrompt,
|
||||
iterateInput,
|
||||
selectedOptimizeModel.value,
|
||||
{
|
||||
onToken: (token: string) => {
|
||||
state.optimizedPrompt += token
|
||||
},
|
||||
onReasoningToken: (reasoningToken: string) => {
|
||||
state.optimizedReasoning += reasoningToken
|
||||
},
|
||||
onComplete: async () => {
|
||||
if (!selectedIterateTemplate.value) {
|
||||
state.isIterating = false
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 保存迭代历史
|
||||
const iterationData = {
|
||||
chainId: state.currentChainId,
|
||||
originalPrompt: originalPrompt,
|
||||
optimizedPrompt: state.optimizedPrompt,
|
||||
iterationNote: iterateInput,
|
||||
modelKey: selectedOptimizeModel.value,
|
||||
templateId: selectedIterateTemplate.value.id
|
||||
}
|
||||
|
||||
const updatedChain = await historyManager.value!.addIteration(iterationData)
|
||||
|
||||
state.currentVersions = updatedChain.versions
|
||||
state.currentVersionId = updatedChain.currentRecord.id
|
||||
|
||||
toast.success(t('toast.success.iterateComplete'))
|
||||
} catch (error: unknown) {
|
||||
console.error('[History] 迭代记录失败:', error)
|
||||
toast.warning(t('toast.warning.historyFailed'))
|
||||
} finally {
|
||||
state.isIterating = false
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
console.error('[Iterate] 迭代失败:', error)
|
||||
toast.error(t('toast.error.iterateFailed'))
|
||||
state.isIterating = false
|
||||
}
|
||||
},
|
||||
selectedIterateTemplate.value.id
|
||||
)
|
||||
} catch (error: unknown) {
|
||||
console.error('[Iterate] 迭代失败:', error)
|
||||
toast.error(t('toast.error.iterateFailed'))
|
||||
state.isIterating = false
|
||||
}
|
||||
},
|
||||
|
||||
// 切换版本
|
||||
switchVersion: async (version: PromptChain['versions'][number]) => {
|
||||
// 强制更新内容,确保UI同步
|
||||
state.optimizedPrompt = version.optimizedPrompt
|
||||
state.currentVersionId = version.id
|
||||
|
||||
// 等待一个微任务确保状态更新完成
|
||||
await nextTick()
|
||||
}
|
||||
})
|
||||
|
||||
// 同步 selectedTemplate 和 selectedIterateTemplate
|
||||
// 这样外部可以通过 props 控制,内部也能访问
|
||||
const syncTemplates = () => {
|
||||
state.selectedTemplate = selectedTemplate.value
|
||||
state.selectedIterateTemplate = selectedIterateTemplate.value
|
||||
}
|
||||
|
||||
// 初始同步
|
||||
syncTemplates()
|
||||
|
||||
// 监听变化并同步(使用 Vue 的响应式系统自动处理)
|
||||
const unwatchTemplate = () => {
|
||||
state.selectedTemplate = selectedTemplate.value
|
||||
}
|
||||
const unwatchIterateTemplate = () => {
|
||||
state.selectedIterateTemplate = selectedIterateTemplate.value
|
||||
}
|
||||
|
||||
// 返回 reactive 对象
|
||||
return state
|
||||
}
|
||||
247
packages/ui/src/composables/prompt/useContextUserTester.ts
Normal file
247
packages/ui/src/composables/prompt/useContextUserTester.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import { reactive, type Ref } from 'vue'
|
||||
import { useToast } from '../ui/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getErrorMessage } from '../../utils/error'
|
||||
import type { AppServices } from '../../types/services'
|
||||
import type { ConversationMessage } from '../../types/variable'
|
||||
import type { VariableManagerHooks } from './useVariableManager'
|
||||
|
||||
/**
|
||||
* ContextUser 模式测试结果接口
|
||||
*/
|
||||
export interface ContextUserTestResults {
|
||||
// 原始提示词结果
|
||||
originalResult: string
|
||||
originalReasoning: string
|
||||
isTestingOriginal: boolean
|
||||
|
||||
// 优化提示词结果
|
||||
optimizedResult: string
|
||||
optimizedReasoning: string
|
||||
isTestingOptimized: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* ContextUser 模式测试器接口
|
||||
*/
|
||||
export interface UseContextUserTester {
|
||||
// 测试结果状态
|
||||
testResults: ContextUserTestResults
|
||||
|
||||
// 方法
|
||||
executeTest: (
|
||||
prompt: string,
|
||||
optimizedPrompt: string,
|
||||
testContent: string,
|
||||
isCompareMode: boolean,
|
||||
testVariables?: Record<string, string>
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* ContextUser 模式提示词测试器 Composable
|
||||
*
|
||||
* 专门用于 ContextUserWorkspace 的测试逻辑,特点:
|
||||
* - 只处理用户模式测试(user mode)
|
||||
* - 独立的测试结果状态管理
|
||||
* - 支持对比模式(原始 vs 优化)
|
||||
* - 与 ContextSystem 的 useConversationTester 对称
|
||||
*
|
||||
* @param services 服务实例引用
|
||||
* @param selectedTestModel 测试模型选择
|
||||
* @param variableManager 变量管理器
|
||||
* @returns ContextUser 测试器接口
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const contextUserTester = useContextUserTester(
|
||||
* services,
|
||||
* computed(() => props.selectedTestModel),
|
||||
* variableManager
|
||||
* )
|
||||
*
|
||||
* // 执行测试
|
||||
* await contextUserTester.executeTest(
|
||||
* prompt,
|
||||
* optimizedPrompt,
|
||||
* testContent,
|
||||
* isCompareMode,
|
||||
* testVariables
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
export function useContextUserTester(
|
||||
services: Ref<AppServices | null>,
|
||||
selectedTestModel: Ref<string>,
|
||||
variableManager: VariableManagerHooks | null
|
||||
): UseContextUserTester {
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 创建响应式状态对象
|
||||
const state = reactive<UseContextUserTester>({
|
||||
// 测试结果状态
|
||||
testResults: {
|
||||
// 原始提示词结果
|
||||
originalResult: '',
|
||||
originalReasoning: '',
|
||||
isTestingOriginal: false,
|
||||
|
||||
// 优化提示词结果
|
||||
optimizedResult: '',
|
||||
optimizedReasoning: '',
|
||||
isTestingOptimized: false,
|
||||
},
|
||||
|
||||
// 执行测试(支持对比模式)
|
||||
executeTest: async (
|
||||
prompt: string,
|
||||
optimizedPrompt: string,
|
||||
testContent: string,
|
||||
isCompareMode: boolean,
|
||||
testVariables?: Record<string, string>
|
||||
) => {
|
||||
if (!services.value?.promptService) {
|
||||
toast.error(t('toast.error.serviceInit'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedTestModel.value) {
|
||||
toast.error(t('test.error.noModel'))
|
||||
return
|
||||
}
|
||||
|
||||
if (isCompareMode) {
|
||||
// 对比模式:测试原始和优化提示词
|
||||
await state.testPromptWithType(
|
||||
'original',
|
||||
prompt,
|
||||
optimizedPrompt,
|
||||
testContent,
|
||||
testVariables
|
||||
)
|
||||
await state.testPromptWithType(
|
||||
'optimized',
|
||||
prompt,
|
||||
optimizedPrompt,
|
||||
testContent,
|
||||
testVariables
|
||||
)
|
||||
} else {
|
||||
// 单一模式:只测试优化后的提示词
|
||||
await state.testPromptWithType(
|
||||
'optimized',
|
||||
prompt,
|
||||
optimizedPrompt,
|
||||
testContent,
|
||||
testVariables
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 测试特定类型的提示词(内部方法)
|
||||
*/
|
||||
testPromptWithType: async (
|
||||
type: 'original' | 'optimized',
|
||||
prompt: string,
|
||||
optimizedPrompt: string,
|
||||
testContent: string,
|
||||
testVars?: Record<string, string>
|
||||
) => {
|
||||
const isOriginal = type === 'original'
|
||||
const selectedPrompt = isOriginal ? prompt : optimizedPrompt
|
||||
|
||||
// 检查提示词
|
||||
if (!selectedPrompt) {
|
||||
toast.error(
|
||||
isOriginal ? t('test.error.noOriginalPrompt') : t('test.error.noOptimizedPrompt')
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置测试状态
|
||||
if (isOriginal) {
|
||||
state.testResults.isTestingOriginal = true
|
||||
state.testResults.originalResult = ''
|
||||
state.testResults.originalReasoning = ''
|
||||
} else {
|
||||
state.testResults.isTestingOptimized = true
|
||||
state.testResults.optimizedResult = ''
|
||||
state.testResults.optimizedReasoning = ''
|
||||
}
|
||||
|
||||
try {
|
||||
const streamHandler = {
|
||||
onToken: (token: string) => {
|
||||
if (isOriginal) {
|
||||
state.testResults.originalResult += token
|
||||
} else {
|
||||
state.testResults.optimizedResult += token
|
||||
}
|
||||
},
|
||||
onReasoningToken: (reasoningToken: string) => {
|
||||
if (isOriginal) {
|
||||
state.testResults.originalReasoning += reasoningToken
|
||||
} else {
|
||||
state.testResults.optimizedReasoning += reasoningToken
|
||||
}
|
||||
},
|
||||
onComplete: () => {
|
||||
// Test completed successfully
|
||||
},
|
||||
onError: (err: Error) => {
|
||||
const errorMessage = err.message || t('test.error.failed')
|
||||
console.error(`[useContextUserTester] ${type} test failed:`, errorMessage)
|
||||
const testTypeKey = type === 'original' ? 'originalTestFailed' : 'optimizedTestFailed'
|
||||
toast.error(`${t(`test.error.${testTypeKey}`)}: ${errorMessage}`)
|
||||
},
|
||||
}
|
||||
|
||||
// ContextUser 模式:提示词作为用户输入
|
||||
// 固定 optimizationMode 为 'user'
|
||||
const systemPrompt = ''
|
||||
const userPrompt = selectedPrompt
|
||||
|
||||
// 变量:合并全局变量 + 测试变量
|
||||
const baseVars = variableManager?.variableManager.value?.resolveAllVariables() || {}
|
||||
const variables = {
|
||||
...baseVars,
|
||||
...(testVars || {}),
|
||||
currentPrompt: selectedPrompt,
|
||||
userQuestion: userPrompt,
|
||||
}
|
||||
|
||||
// 构造简单的消息列表(ContextUser 模式只有用户消息)
|
||||
const messages: ConversationMessage[] = [
|
||||
{ role: 'user' as const, content: userPrompt },
|
||||
]
|
||||
|
||||
// 使用自定义会话测试
|
||||
await services.value!.promptService.testCustomConversationStream(
|
||||
{
|
||||
modelKey: selectedTestModel.value,
|
||||
messages,
|
||||
variables,
|
||||
tools: [], // ContextUser 模式基础不支持工具调用(如需支持可扩展)
|
||||
},
|
||||
streamHandler
|
||||
)
|
||||
} catch (error: unknown) {
|
||||
console.error(`[useContextUserTester] ${type} test error:`, error)
|
||||
const errorMessage = getErrorMessage(error) || t('test.error.failed')
|
||||
const testTypeKey = type === 'original' ? 'originalTestFailed' : 'optimizedTestFailed'
|
||||
toast.error(`${t(`test.error.${testTypeKey}`)}: ${errorMessage}`)
|
||||
} finally {
|
||||
// 重置测试状态
|
||||
if (isOriginal) {
|
||||
state.testResults.isTestingOriginal = false
|
||||
} else {
|
||||
state.testResults.isTestingOptimized = false
|
||||
}
|
||||
}
|
||||
},
|
||||
} as UseContextUserTester)
|
||||
|
||||
return state
|
||||
}
|
||||
201
packages/ui/src/composables/prompt/useConversationTester.ts
Normal file
201
packages/ui/src/composables/prompt/useConversationTester.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import { reactive, type Ref, type ComputedRef } from 'vue'
|
||||
import { useToast } from '../ui/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getErrorMessage } from '../../utils/error'
|
||||
import type { OptimizationMode, ToolDefinition, ToolCall, ToolCallResult, ConversationMessage } from '@prompt-optimizer/core'
|
||||
import type { AppServices } from '../../types/services'
|
||||
import type { VariableManagerHooks } from './useVariableManager'
|
||||
import type { TestAreaPanelInstance } from '../../components/types/test-area'
|
||||
|
||||
/**
|
||||
* 多对话模式专用测试 Composable
|
||||
*
|
||||
* 专门处理上下文-多消息模式的测试逻辑,包括:
|
||||
* - 选中消息的 V0 对比
|
||||
* - 会话上下文处理
|
||||
* - 工具调用支持
|
||||
*
|
||||
* @param services 服务实例引用
|
||||
* @param selectedTestModel 测试模型选择
|
||||
* @param optimizationContext 优化上下文(会话消息)
|
||||
* @param optimizationContextTools 上下文工具列表
|
||||
* @param variableManager 变量管理器
|
||||
* @param selectedMessageId 当前选中的消息ID(用于对比模式)
|
||||
* @returns 多对话测试接口
|
||||
*/
|
||||
export function useConversationTester(
|
||||
services: Ref<AppServices | null>,
|
||||
selectedTestModel: Ref<string>,
|
||||
optimizationContext: Ref<ConversationMessage[]>,
|
||||
optimizationContextTools: Ref<ToolDefinition[]>,
|
||||
variableManager: VariableManagerHooks | null,
|
||||
selectedMessageId?: Ref<string>
|
||||
) {
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
const state = reactive({
|
||||
testResults: {
|
||||
originalResult: '',
|
||||
originalReasoning: '',
|
||||
isTestingOriginal: false,
|
||||
|
||||
optimizedResult: '',
|
||||
optimizedReasoning: '',
|
||||
isTestingOptimized: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* 执行多对话测试(支持对比模式)
|
||||
* @param isCompareMode 是否对比模式
|
||||
* @param testVariables 测试变量
|
||||
* @param testPanelRef 测试面板引用(用于工具调用回调)
|
||||
*/
|
||||
executeTest: async (
|
||||
isCompareMode: boolean,
|
||||
testVariables?: Record<string, string>,
|
||||
testPanelRef?: TestAreaPanelInstance | null
|
||||
) => {
|
||||
if (!services.value?.promptService) {
|
||||
toast.error(t('toast.error.serviceInit'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedTestModel.value) {
|
||||
toast.error(t('test.error.noModel'))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查会话上下文
|
||||
if (!optimizationContext.value || optimizationContext.value.length === 0) {
|
||||
toast.error(t('test.error.noConversation'))
|
||||
return
|
||||
}
|
||||
|
||||
if (isCompareMode) {
|
||||
// 对比模式:并发测试原始和优化会话
|
||||
const originalTestPromise = state.testConversation('original', testVariables, testPanelRef)
|
||||
const optimizedTestPromise = state.testConversation('optimized', testVariables, testPanelRef)
|
||||
await Promise.all([originalTestPromise, optimizedTestPromise])
|
||||
} else {
|
||||
// 单一模式:只测试优化后的会话
|
||||
await state.testConversation('optimized', testVariables, testPanelRef)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 测试特定类型的会话(原始 vs 优化)
|
||||
*/
|
||||
testConversation: async (
|
||||
type: 'original' | 'optimized',
|
||||
testVars?: Record<string, string>,
|
||||
testPanelRef?: TestAreaPanelInstance | null
|
||||
) => {
|
||||
const isOriginal = type === 'original'
|
||||
|
||||
// 设置测试状态
|
||||
if (isOriginal) {
|
||||
state.testResults.isTestingOriginal = true
|
||||
state.testResults.originalResult = ''
|
||||
state.testResults.originalReasoning = ''
|
||||
} else {
|
||||
state.testResults.isTestingOptimized = true
|
||||
state.testResults.optimizedResult = ''
|
||||
state.testResults.optimizedReasoning = ''
|
||||
}
|
||||
|
||||
// 清除对应类型的工具调用数据
|
||||
testPanelRef?.clearToolCalls(isOriginal ? 'original' : 'optimized')
|
||||
|
||||
try {
|
||||
const streamHandler = {
|
||||
onToken: (token: string) => {
|
||||
if (isOriginal) {
|
||||
state.testResults.originalResult += token
|
||||
} else {
|
||||
state.testResults.optimizedResult += token
|
||||
}
|
||||
},
|
||||
onReasoningToken: (reasoningToken: string) => {
|
||||
if (isOriginal) {
|
||||
state.testResults.originalReasoning += reasoningToken
|
||||
} else {
|
||||
state.testResults.optimizedReasoning += reasoningToken
|
||||
}
|
||||
},
|
||||
onComplete: () => {
|
||||
// Test completed successfully
|
||||
},
|
||||
onError: (err: Error) => {
|
||||
const errorMessage = err.message || t('test.error.failed')
|
||||
console.error(`[useConversationTester] ${type} test failed:`, errorMessage)
|
||||
const testTypeKey = type === 'original' ? 'originalTestFailed' : 'optimizedTestFailed'
|
||||
toast.error(`${t(`test.error.${testTypeKey}`)}: ${errorMessage}`)
|
||||
},
|
||||
}
|
||||
|
||||
// 变量:合并全局变量 + 测试变量
|
||||
const baseVars = variableManager?.variableManager.value?.resolveAllVariables() || {}
|
||||
const variables = {
|
||||
...baseVars,
|
||||
...(testVars || {}),
|
||||
}
|
||||
|
||||
// 构造会话消息:
|
||||
// - 原始会话(original):只有选中的消息使用 originalContent(V0),其他消息使用当前版本
|
||||
// - 优化会话(optimized):所有消息都使用当前版本
|
||||
const messages: ConversationMessage[] = isOriginal
|
||||
? optimizationContext.value.map(msg => ({
|
||||
...msg,
|
||||
content: (selectedMessageId?.value && msg.id === selectedMessageId.value)
|
||||
? (msg.originalContent || msg.content)
|
||||
: msg.content
|
||||
}))
|
||||
: optimizationContext.value
|
||||
|
||||
// 检查是否有工具
|
||||
const hasTools = optimizationContextTools.value?.length > 0
|
||||
|
||||
// 使用自定义会话测试
|
||||
await services.value!.promptService.testCustomConversationStream(
|
||||
{
|
||||
modelKey: selectedTestModel.value,
|
||||
messages,
|
||||
variables,
|
||||
tools: hasTools ? optimizationContextTools.value : [],
|
||||
},
|
||||
{
|
||||
...streamHandler,
|
||||
onToolCall: (toolCall: ToolCall) => {
|
||||
if (!hasTools) return
|
||||
console.log(
|
||||
`[useConversationTester] ${type} test tool call received:`,
|
||||
toolCall
|
||||
)
|
||||
const toolCallResult: ToolCallResult = {
|
||||
toolCall,
|
||||
status: 'success',
|
||||
timestamp: new Date(),
|
||||
}
|
||||
testPanelRef?.handleToolCall(toolCallResult, type)
|
||||
},
|
||||
}
|
||||
)
|
||||
} catch (error: unknown) {
|
||||
console.error(`[useConversationTester] ${type} test error:`, error)
|
||||
const errorMessage = getErrorMessage(error) || t('test.error.failed')
|
||||
const testTypeKey = type === 'original' ? 'originalTestFailed' : 'optimizedTestFailed'
|
||||
toast.error(`${t(`test.error.${testTypeKey}`)}: ${errorMessage}`)
|
||||
} finally {
|
||||
// 重置测试状态
|
||||
if (isOriginal) {
|
||||
state.testResults.isTestingOriginal = false
|
||||
} else {
|
||||
state.testResults.isTestingOptimized = false
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return state
|
||||
}
|
||||
148
packages/ui/src/composables/prompt/usePromptDisplayAdapter.ts
Normal file
148
packages/ui/src/composables/prompt/usePromptDisplayAdapter.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { computed, type Ref, type ComputedRef } from 'vue'
|
||||
import type { ConversationMessage, PromptRecord } from '@prompt-optimizer/core'
|
||||
import type { UseConversationOptimization } from './useConversationOptimization'
|
||||
|
||||
/**
|
||||
* 提示词显示适配器选项
|
||||
*/
|
||||
export interface PromptDisplayAdapterOptions {
|
||||
// 启用消息优化模式
|
||||
enableMessageOptimization: Ref<boolean>
|
||||
|
||||
// 上下文消息列表
|
||||
optimizationContext: Ref<ConversationMessage[]>
|
||||
|
||||
// 全局优化链(用于历史记录查看)
|
||||
globalVersions: Ref<PromptRecord[]>
|
||||
globalCurrentVersionId: Ref<string | undefined>
|
||||
globalIsOptimizing: Ref<boolean>
|
||||
}
|
||||
|
||||
/**
|
||||
* 提示词显示适配器返回值
|
||||
*/
|
||||
export interface UsePromptDisplayAdapter {
|
||||
// 模式标识
|
||||
isInMessageOptimizationMode: ComputedRef<boolean>
|
||||
|
||||
// 显示数据(自动根据模式切换数据源)
|
||||
displayedOriginalPrompt: ComputedRef<string>
|
||||
displayedOptimizedPrompt: ComputedRef<string>
|
||||
displayedVersions: ComputedRef<PromptRecord[]>
|
||||
displayedCurrentVersionId: ComputedRef<string | null>
|
||||
displayedIsOptimizing: ComputedRef<boolean>
|
||||
}
|
||||
|
||||
/**
|
||||
* 提示词显示适配器 Composable
|
||||
*
|
||||
* 功能:
|
||||
* - 根据"消息优化模式 vs 历史记录查看模式"自动切换数据源
|
||||
* - 为 PromptPanel 提供统一的数据接口
|
||||
* - 解决消息级优化和全局优化的数据隔离问题
|
||||
*
|
||||
* 使用场景:
|
||||
* - ContextSystemWorkspace: 需要在消息优化和历史记录查看之间切换
|
||||
* - 其他需要类似适配逻辑的组件
|
||||
*
|
||||
* @param conversationOptimization - 会话优化 composable 实例
|
||||
* @param options - 适配器配置选项
|
||||
* @returns 显示层数据和模式标识
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const displayAdapter = usePromptDisplayAdapter(
|
||||
* conversationOptimization,
|
||||
* {
|
||||
* enableMessageOptimization: computed(() => props.enableMessageOptimization),
|
||||
* optimizationContext: computed(() => props.optimizationContext),
|
||||
* globalVersions: computed(() => props.versions || []),
|
||||
* globalCurrentVersionId: computed(() => props.currentVersionId),
|
||||
* globalIsOptimizing: computed(() => props.isOptimizing),
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
export function usePromptDisplayAdapter(
|
||||
conversationOptimization: UseConversationOptimization,
|
||||
options: PromptDisplayAdapterOptions
|
||||
): UsePromptDisplayAdapter {
|
||||
const selectedMessageId = conversationOptimization.selectedMessageId
|
||||
|
||||
/**
|
||||
* 消息优化模式判定
|
||||
* 只有在启用消息优化 且 有选中消息时,才进入消息优化模式
|
||||
*/
|
||||
const isInMessageOptimizationMode = computed(() => {
|
||||
return options.enableMessageOptimization.value && !!selectedMessageId.value
|
||||
})
|
||||
|
||||
/**
|
||||
* 显示的原始提示词
|
||||
* - 消息优化模式: 当前选中消息的原始内容
|
||||
* - 历史记录模式: 空字符串(不显示)
|
||||
*/
|
||||
const displayedOriginalPrompt = computed(() => {
|
||||
if (!isInMessageOptimizationMode.value) return ''
|
||||
|
||||
const message = options.optimizationContext.value?.find(
|
||||
m => m.id === selectedMessageId.value
|
||||
)
|
||||
return message?.originalContent || message?.content || ''
|
||||
})
|
||||
|
||||
/**
|
||||
* 显示的优化结果
|
||||
* - 消息优化模式: 消息级优化结果
|
||||
* - 历史记录模式: 空字符串(不显示)
|
||||
*/
|
||||
const displayedOptimizedPrompt = computed(() => {
|
||||
return isInMessageOptimizationMode.value
|
||||
? conversationOptimization.optimizedPrompt.value
|
||||
: ''
|
||||
})
|
||||
|
||||
/**
|
||||
* 显示的版本列表
|
||||
* - 消息优化模式: 消息级优化版本链
|
||||
* - 历史记录模式: 全局优化版本链
|
||||
*/
|
||||
const displayedVersions = computed(() => {
|
||||
if (isInMessageOptimizationMode.value) {
|
||||
return conversationOptimization.currentVersions.value || []
|
||||
}
|
||||
return options.globalVersions.value || []
|
||||
})
|
||||
|
||||
/**
|
||||
* 显示的当前版本 ID
|
||||
* - 消息优化模式: 消息级当前版本 ID
|
||||
* - 历史记录模式: 全局当前版本 ID
|
||||
*/
|
||||
const displayedCurrentVersionId = computed(() => {
|
||||
if (isInMessageOptimizationMode.value) {
|
||||
return conversationOptimization.currentRecordId.value || null
|
||||
}
|
||||
return options.globalCurrentVersionId.value || null
|
||||
})
|
||||
|
||||
/**
|
||||
* 显示的优化中状态
|
||||
* - 消息优化模式: 消息级优化状态
|
||||
* - 历史记录模式: 全局优化状态
|
||||
*/
|
||||
const displayedIsOptimizing = computed(() => {
|
||||
return isInMessageOptimizationMode.value
|
||||
? conversationOptimization.isOptimizing.value
|
||||
: options.globalIsOptimizing.value
|
||||
})
|
||||
|
||||
return {
|
||||
isInMessageOptimizationMode,
|
||||
displayedOriginalPrompt,
|
||||
displayedOptimizedPrompt,
|
||||
displayedVersions,
|
||||
displayedCurrentVersionId,
|
||||
displayedIsOptimizing,
|
||||
}
|
||||
}
|
||||
@@ -296,8 +296,9 @@ export function usePromptOptimizer(
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
originalContent: msg.originalContent,
|
||||
chainId: (msg as any).chainId,
|
||||
appliedVersion: (msg as any).appliedVersion
|
||||
// 运行时属性:消息被优化后动态添加的元数据
|
||||
chainId: (msg as Record<string, unknown>).chainId as string | undefined,
|
||||
appliedVersion: (msg as Record<string, unknown>).appliedVersion as number | undefined
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,26 +3,25 @@ import { reactive, type Ref, type ComputedRef } from 'vue'
|
||||
import { useToast } from '../ui/useToast'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getErrorMessage } from '../../utils/error'
|
||||
import type { OptimizationMode, ToolDefinition, ToolCall, ToolCallResult } from '@prompt-optimizer/core'
|
||||
import type { OptimizationMode } from '@prompt-optimizer/core'
|
||||
import type { AppServices } from '../../types/services'
|
||||
import type { ConversationMessage } from '../../types/variable'
|
||||
import type { VariableManagerHooks } from './useVariableManager'
|
||||
import type { TestAreaPanelInstance } from '../components/types/test-area'
|
||||
|
||||
/**
|
||||
* 高级提示词测试 Hook
|
||||
* 支持变量注入、上下文、工具调用等高级特性
|
||||
* 基础模式提示词测试 Composable
|
||||
*
|
||||
* 专门处理基础模式的提示词测试,支持:
|
||||
* - System prompt 测试
|
||||
* - User prompt 测试
|
||||
* - 变量注入
|
||||
* - 对比模式(原始 vs 优化)
|
||||
*
|
||||
* @param services 服务实例引用
|
||||
* @param selectedTestModel 测试模型选择
|
||||
* @param optimizationMode 当前优化模式(建议传入 computed 值,从 basicSubMode/proSubMode 动态计算)
|
||||
* @param advancedModeEnabled 是否启用高级模式
|
||||
* @param optimizationContext 优化上下文(会话消息)
|
||||
* @param optimizationContextTools 上下文工具列表
|
||||
* @param optimizationMode 当前优化模式
|
||||
* @param variableManager 变量管理器
|
||||
* @param selectedMessageId 当前选中的消息ID(用于对比模式)
|
||||
* @returns 提示词测试接口
|
||||
* @deprecated optimizationMode 参数建议传入 computed 值(从 basicSubMode/proSubMode 动态计算)
|
||||
* @returns 基础测试接口
|
||||
*/
|
||||
type OptimizationModeSource = Ref<OptimizationMode> | ComputedRef<OptimizationMode>
|
||||
|
||||
@@ -30,11 +29,7 @@ export function usePromptTester(
|
||||
services: Ref<AppServices | null>,
|
||||
selectedTestModel: Ref<string>,
|
||||
optimizationMode: OptimizationModeSource,
|
||||
advancedModeEnabled: Ref<boolean>,
|
||||
optimizationContext: Ref<ConversationMessage[]>,
|
||||
optimizationContextTools: Ref<ToolDefinition[]>,
|
||||
variableManager: VariableManagerHooks | null,
|
||||
selectedMessageId?: Ref<string>
|
||||
variableManager: VariableManagerHooks | null
|
||||
) {
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
@@ -56,21 +51,19 @@ export function usePromptTester(
|
||||
|
||||
// Methods
|
||||
/**
|
||||
* 执行测试(支持对比模式)
|
||||
* 执行基础模式测试(支持对比模式)
|
||||
* @param prompt 原始提示词
|
||||
* @param optimizedPrompt 优化后的提示词
|
||||
* @param testContent 测试内容
|
||||
* @param isCompareMode 是否对比模式
|
||||
* @param testVariables 测试变量
|
||||
* @param testPanelRef 测试面板引用(用于工具调用回调)
|
||||
*/
|
||||
executeTest: async (
|
||||
prompt: string,
|
||||
optimizedPrompt: string,
|
||||
testContent: string,
|
||||
isCompareMode: boolean,
|
||||
testVariables?: Record<string, string>,
|
||||
testPanelRef?: TestAreaPanelInstance | null
|
||||
testVariables?: Record<string, string>
|
||||
) => {
|
||||
if (!services.value?.promptService) {
|
||||
toast.error(t('toast.error.serviceInit'))
|
||||
@@ -89,16 +82,14 @@ export function usePromptTester(
|
||||
prompt,
|
||||
optimizedPrompt,
|
||||
testContent,
|
||||
testVariables,
|
||||
testPanelRef
|
||||
testVariables
|
||||
)
|
||||
await state.testPromptWithType(
|
||||
'optimized',
|
||||
prompt,
|
||||
optimizedPrompt,
|
||||
testContent,
|
||||
testVariables,
|
||||
testPanelRef
|
||||
testVariables
|
||||
)
|
||||
} else {
|
||||
// 单一模式:只测试优化后的提示词
|
||||
@@ -107,34 +98,26 @@ export function usePromptTester(
|
||||
prompt,
|
||||
optimizedPrompt,
|
||||
testContent,
|
||||
testVariables,
|
||||
testPanelRef
|
||||
testVariables
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 测试特定类型的提示词(复用会话上下文 + 变量 + 工具)
|
||||
* 测试特定类型的提示词(基础模式)
|
||||
*/
|
||||
testPromptWithType: async (
|
||||
type: 'original' | 'optimized',
|
||||
prompt: string,
|
||||
optimizedPrompt: string,
|
||||
testContent: string,
|
||||
testVars?: Record<string, string>,
|
||||
testPanelRef?: TestAreaPanelInstance | null
|
||||
testVars?: Record<string, string>
|
||||
) => {
|
||||
const isOriginal = type === 'original'
|
||||
const selectedPrompt = isOriginal ? prompt : optimizedPrompt
|
||||
|
||||
// 🔧 检查会话上下文
|
||||
const hasConversationContext =
|
||||
optimizationMode.value === 'system' &&
|
||||
advancedModeEnabled.value &&
|
||||
(optimizationContext.value?.length || 0) > 0
|
||||
|
||||
// 🔧 在上下文-多消息模式下,会话内容来自 optimizationContext,不需要检查 selectedPrompt
|
||||
if (!hasConversationContext && !selectedPrompt) {
|
||||
// 检查提示词
|
||||
if (!selectedPrompt) {
|
||||
toast.error(
|
||||
isOriginal ? t('test.error.noOriginalPrompt') : t('test.error.noOptimizedPrompt')
|
||||
)
|
||||
@@ -152,9 +135,6 @@ export function usePromptTester(
|
||||
state.testResults.optimizedReasoning = ''
|
||||
}
|
||||
|
||||
// 清除对应类型的工具调用数据
|
||||
testPanelRef?.clearToolCalls(isOriginal ? 'original' : 'optimized')
|
||||
|
||||
try {
|
||||
const streamHandler = {
|
||||
onToken: (token: string) => {
|
||||
@@ -182,7 +162,7 @@ export function usePromptTester(
|
||||
},
|
||||
}
|
||||
|
||||
// 统一构造对话与变量,尽量复用上下文
|
||||
// 构造系统消息和用户消息
|
||||
let systemPrompt = ''
|
||||
let userPrompt = ''
|
||||
|
||||
@@ -196,76 +176,30 @@ export function usePromptTester(
|
||||
userPrompt = testContent || '请按照你的角色设定,展示你的能力并与我互动。'
|
||||
}
|
||||
|
||||
const hasConversationContext =
|
||||
optimizationMode.value === 'system' &&
|
||||
advancedModeEnabled.value &&
|
||||
(optimizationContext.value?.length || 0) > 0
|
||||
const hasTools =
|
||||
advancedModeEnabled.value &&
|
||||
(optimizationContextTools.value?.length || 0) > 0
|
||||
|
||||
// 变量:合并全局变量 + 测试变量 + 当前提示词/问题(用于会话模板中的占位符)
|
||||
// 按优先级合并: 全局自定义变量 < 测试变量 < 预定义变量
|
||||
const baseVars =
|
||||
variableManager?.variableManager.value?.resolveAllVariables() || {}
|
||||
|
||||
// 使用传入的测试变量
|
||||
// 变量:合并全局变量 + 测试变量
|
||||
const baseVars = variableManager?.variableManager.value?.resolveAllVariables() || {}
|
||||
const variables = {
|
||||
...baseVars,
|
||||
...(testVars || {}), // 测试变量优先级高于全局变量
|
||||
...(testVars || {}),
|
||||
currentPrompt: selectedPrompt,
|
||||
userQuestion: userPrompt,
|
||||
}
|
||||
|
||||
// 对话构造逻辑:
|
||||
// - 系统模式 + 有会话上下文:
|
||||
// - 原始会话(original):只有选中的消息使用 originalContent(V0),其他消息使用当前版本
|
||||
// - 优化会话(optimized):所有消息都使用当前版本
|
||||
// - 用户模式:无论是否有会话上下文,都直接发送优化后的提示词作为用户消息
|
||||
// (因为用户提示词优化的目标是生成可直接使用的单条用户消息)
|
||||
const messages: ConversationMessage[] =
|
||||
optimizationMode.value === 'system' && hasConversationContext
|
||||
? isOriginal
|
||||
// 🆕 原始会话:只有选中的消息使用 V0,其他消息保持当前版本
|
||||
? optimizationContext.value.map(msg => ({
|
||||
...msg,
|
||||
content: (selectedMessageId?.value && msg.id === selectedMessageId.value)
|
||||
? (msg.originalContent || msg.content)
|
||||
: msg.content
|
||||
}))
|
||||
// 优化会话:所有消息都使用当前版本
|
||||
: optimizationContext.value
|
||||
: [
|
||||
...(systemPrompt
|
||||
? [{ role: 'system' as const, content: systemPrompt }]
|
||||
: []),
|
||||
{ role: 'user' as const, content: userPrompt },
|
||||
]
|
||||
// 构造简单的消息列表
|
||||
const messages: ConversationMessage[] = [
|
||||
...(systemPrompt ? [{ role: 'system' as const, content: systemPrompt }] : []),
|
||||
{ role: 'user' as const, content: userPrompt },
|
||||
]
|
||||
|
||||
// 统一使用自定义会话测试,以便支持上下文与工具
|
||||
// 使用自定义会话测试
|
||||
await services.value!.promptService.testCustomConversationStream(
|
||||
{
|
||||
modelKey: selectedTestModel.value,
|
||||
messages,
|
||||
variables,
|
||||
tools: hasTools ? optimizationContextTools.value : [],
|
||||
tools: [], // 基础模式不支持工具调用
|
||||
},
|
||||
{
|
||||
...streamHandler,
|
||||
onToolCall: (toolCall: ToolCall) => {
|
||||
if (!hasTools) return
|
||||
console.log(
|
||||
`[usePromptTester] ${type} test tool call received:`,
|
||||
toolCall
|
||||
)
|
||||
const toolCallResult: ToolCallResult = {
|
||||
toolCall,
|
||||
status: 'success',
|
||||
timestamp: new Date(),
|
||||
}
|
||||
testPanelRef?.handleToolCall(toolCallResult, type)
|
||||
},
|
||||
}
|
||||
streamHandler
|
||||
)
|
||||
} catch (error: unknown) {
|
||||
console.error(`[usePromptTester] ${type} test error:`, error)
|
||||
|
||||
@@ -186,7 +186,6 @@
|
||||
@compare-toggle="handleTestAreaCompareToggle"
|
||||
@optimize="handleOptimizePrompt"
|
||||
@iterate="handleIteratePrompt"
|
||||
@test="handleTestAreaTest"
|
||||
@switch-version="handleSwitchVersion"
|
||||
@save-favorite="handleSaveFavorite"
|
||||
@open-global-variables="openVariableManager()"
|
||||
@@ -196,20 +195,10 @@
|
||||
@config-model="modelManager.showConfig = true"
|
||||
@open-input-preview="handleOpenInputPreview"
|
||||
@open-prompt-preview="handleOpenPromptPreview"
|
||||
:selected-message-id="conversationOptimization.selectedMessageId.value"
|
||||
:enable-message-optimization="true"
|
||||
@message-select="handleMessageSelect"
|
||||
:message-optimized-prompt="conversationOptimization.optimizedPrompt.value"
|
||||
:message-versions="conversationOptimization.currentVersions.value"
|
||||
:message-current-version-id="conversationOptimization.currentRecordId.value"
|
||||
:is-message-optimizing="conversationOptimization.isOptimizing.value"
|
||||
:versions="optimizer.currentVersions"
|
||||
:current-version-id="optimizer.currentVersionId"
|
||||
@message-switch-version="handleMessageSwitchVersion"
|
||||
@message-switch-to-v0="handleMessageSwitchToV0"
|
||||
@optimize-message="handleOptimizeMessage"
|
||||
@message-change="handleMessageChange"
|
||||
@message-apply-version="handleApplyMessageVersion"
|
||||
:selected-optimize-model="modelManager.selectedOptimizeModel"
|
||||
:selected-template="currentSelectedTemplate"
|
||||
:selected-test-model="modelManager.selectedTestModel"
|
||||
>
|
||||
<!-- 优化模型选择插槽 -->
|
||||
<template #optimize-model-select>
|
||||
@@ -278,58 +267,17 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 测试结果插槽 -->
|
||||
<template #original-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.originalResult"
|
||||
:reasoning="testResults.originalReasoning"
|
||||
:streaming="testResults.isTestingOriginal"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #optimized-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #single-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
<!-- 🔧 测试结果插槽已移除:ContextSystemWorkspace 内部直接使用 useConversationTester 渲染 -->
|
||||
</ContextSystemWorkspace>
|
||||
|
||||
<!-- 上下文-用户模式 -->
|
||||
<!-- 上下文-用户模式(🆕 已独立,内部管理优化和测试逻辑) -->
|
||||
<ContextUserWorkspace
|
||||
ref="userWorkspaceRef"
|
||||
v-else-if="contextMode === 'user'"
|
||||
:prompt="optimizer.prompt"
|
||||
@update:prompt="optimizer.prompt = $event"
|
||||
:optimized-prompt="optimizer.optimizedPrompt"
|
||||
@update:optimizedPrompt="
|
||||
optimizer.optimizedPrompt = $event
|
||||
"
|
||||
:optimized-reasoning="optimizer.optimizedReasoning"
|
||||
:optimization-mode="selectedOptimizationMode"
|
||||
:is-optimizing="optimizer.isOptimizing"
|
||||
:is-iterating="optimizer.isIterating"
|
||||
:is-test-running="false"
|
||||
:versions="optimizer.currentVersions"
|
||||
:current-version-id="optimizer.currentVersionId"
|
||||
:selected-optimize-model="modelManager.selectedOptimizeModel"
|
||||
:selected-test-model="modelManager.selectedTestModel"
|
||||
:selected-template="selectedTemplate"
|
||||
:selected-iterate-template="
|
||||
optimizer.selectedIterateTemplate
|
||||
"
|
||||
@@ -363,11 +311,7 @@
|
||||
:result-vertical-layout="
|
||||
responsiveLayout.isMobile.value
|
||||
"
|
||||
@optimize="handleOptimizePrompt"
|
||||
@iterate="handleIteratePrompt"
|
||||
@test="handleTestAreaTest"
|
||||
@compare-toggle="handleTestAreaCompareToggle"
|
||||
@switch-version="handleSwitchVersion"
|
||||
@save-favorite="handleSaveFavorite"
|
||||
@open-global-variables="openVariableManager()"
|
||||
@open-tool-manager="
|
||||
@@ -447,39 +391,7 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 测试结果插槽 -->
|
||||
<template #original-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.originalResult"
|
||||
:reasoning="testResults.originalReasoning"
|
||||
:streaming="testResults.isTestingOriginal"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #optimized-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #single-result>
|
||||
<OutputDisplay
|
||||
:content="testResults.optimizedResult"
|
||||
:reasoning="testResults.optimizedReasoning"
|
||||
:streaming="testResults.isTestingOptimized"
|
||||
:enableDiff="false"
|
||||
mode="readonly"
|
||||
:style="{ height: '100%', minHeight: '0' }"
|
||||
/>
|
||||
</template>
|
||||
<!-- 🔧 测试结果插槽已移除:ContextUserWorkspace 内部直接使用 useContextUserTester 渲染 -->
|
||||
</ContextUserWorkspace>
|
||||
</template>
|
||||
|
||||
@@ -1028,7 +940,6 @@ import {
|
||||
useContextManagement,
|
||||
useAggregatedVariables,
|
||||
useContextEditorUIState,
|
||||
useConversationOptimization,
|
||||
|
||||
// i18n functions
|
||||
initializeI18nWithStorage,
|
||||
@@ -1087,7 +998,7 @@ watch(
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 4. 向子组件提供服务
|
||||
// 4. 向子组件提供服务(部分 provide 移至声明后)
|
||||
provide("services", services);
|
||||
|
||||
// 5. 控制主UI渲染的标志
|
||||
@@ -1331,72 +1242,19 @@ const handleContextEditorStateUpdate =
|
||||
contextManagement.handleContextEditorStateUpdate;
|
||||
const handleContextModeChange = contextManagement.handleContextModeChange;
|
||||
|
||||
// 🆕 多轮对话消息优化管理
|
||||
const selectedOptimizationTemplate = computed<Template | null>(() => {
|
||||
return selectedOptimizationMode.value === "system"
|
||||
? optimizer.selectedOptimizeTemplate
|
||||
: optimizer.selectedUserOptimizeTemplate;
|
||||
});
|
||||
// 🔧 提供依赖给子组件(必须在所有依赖项声明之后)
|
||||
provide("variableManager", variableManager);
|
||||
provide("optimizationContextTools", optimizationContextTools);
|
||||
|
||||
const conversationOptimization = useConversationOptimization(
|
||||
services,
|
||||
optimizationContext,
|
||||
selectedOptimizationMode,
|
||||
toRef(modelManager, "selectedOptimizeModel"),
|
||||
selectedOptimizationTemplate,
|
||||
toRef(optimizer, "selectedIterateTemplate") // 🔧 添加迭代模板
|
||||
);
|
||||
|
||||
provide('conversationOptimization', conversationOptimization);
|
||||
|
||||
// 处理消息选择事件
|
||||
const handleMessageSelect = async (message: ConversationMessage) => {
|
||||
await conversationOptimization.selectMessage(message);
|
||||
};
|
||||
|
||||
// 处理消息版本切换
|
||||
const handleMessageSwitchVersion = async (version: PromptRecordChain['versions'][number]) => {
|
||||
await conversationOptimization.switchVersion(version);
|
||||
};
|
||||
|
||||
// 🆕 处理消息 V0 切换
|
||||
const handleMessageSwitchToV0 = async (version: PromptRecordChain['versions'][number]) => {
|
||||
await conversationOptimization.switchToV0(version);
|
||||
};
|
||||
|
||||
// 处理消息优化
|
||||
const handleOptimizeMessage = async () => {
|
||||
await conversationOptimization.optimizeMessage();
|
||||
};
|
||||
|
||||
// 处理消息变更(用于清理删除消息的映射)
|
||||
const handleMessageChange = (index: number, message: ConversationMessage, action: 'add' | 'update' | 'delete') => {
|
||||
if (!message?.id) return;
|
||||
if (action === 'delete') {
|
||||
conversationOptimization.cleanupDeletedMessageMapping(message.id);
|
||||
} else if (action === 'update') {
|
||||
conversationOptimization.cleanupDeletedMessageMapping(message.id, { keepSelection: true });
|
||||
}
|
||||
};
|
||||
|
||||
// 手动应用所选版本
|
||||
const handleApplyMessageVersion = async () => {
|
||||
await conversationOptimization.applyCurrentVersion();
|
||||
};
|
||||
|
||||
// 🆕 提示词测试管理(支持变量注入、上下文、工具调用)
|
||||
// 🆕 基础模式提示词测试(简化后只用于基础模式和 context-user)
|
||||
const promptTester = usePromptTester(
|
||||
services as any,
|
||||
toRef(modelManager, 'selectedTestModel'),
|
||||
selectedOptimizationMode, // 保持兼容性,后续应改为使用 basicSubMode/proSubMode
|
||||
advancedModeEnabled,
|
||||
optimizationContext,
|
||||
optimizationContextTools,
|
||||
variableManager,
|
||||
conversationOptimization.selectedMessageId // 🆕 传递选中的消息ID用于对比
|
||||
selectedOptimizationMode,
|
||||
variableManager
|
||||
);
|
||||
|
||||
// 测试结果引用(从 promptTester 获取)
|
||||
// 测试结果引用(从 promptTester 获取,用于基础模式和 context-user)
|
||||
const testResults = computed(() => promptTester.testResults);
|
||||
|
||||
// 处理测试面板的变量变化(现在测试变量由TestAreaPanel自己管理,不需要同步到会话)
|
||||
@@ -2276,20 +2134,16 @@ const getActiveTestPanelInstance = (): TestAreaPanelInstance | null => {
|
||||
return null;
|
||||
};
|
||||
|
||||
// 真实测试处理函数
|
||||
// 基础模式和 context-user 模式的测试处理函数
|
||||
// 注意:context-system 模式已在 ContextSystemWorkspace 内部使用 useConversationTester 处理,不会调用此函数
|
||||
const handleTestAreaTest = async (testVariables?: Record<string, string>) => {
|
||||
// 🔧 多轮对话模式(context-system)下,不使用 testContent(测试内容来自会话消息)
|
||||
// 但现在支持对比模式了,可以对比选中消息的 V0 和当前版本
|
||||
const actualTestContent = contextMode.value === 'system' ? '' : testContent.value;
|
||||
|
||||
// 调用 promptTester 的 executeTest 方法
|
||||
// 调用基础测试器(只用于基础模式和 context-user)
|
||||
await promptTester.executeTest(
|
||||
optimizer.prompt,
|
||||
optimizer.optimizedPrompt,
|
||||
actualTestContent,
|
||||
isCompareMode.value, // 🔧 直接使用 isCompareMode,不再强制为 false
|
||||
testVariables,
|
||||
getActiveTestPanelInstance()
|
||||
testContent.value,
|
||||
isCompareMode.value,
|
||||
testVariables
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user