Skip to content

Commit c8e06bd

Browse files
committed
feat: 优化上下文模式架构,增强变量管理并修复核心功能
本次提交主要围绕上下文模式进行大规模重构与功能增强,并修复了关键的变量注入和模型初始化问题。 **核心重构与功能增强** - **上下文模式架构优化**: - 将 `ContextWorkspace` 拆分为 `ContextSystemWorkspace` 和 `ContextUserWorkspace`,使组件职责更单一,消除内部条件逻辑。 - 优化组件目录结构,按功能模块组织(如 `components/context-mode/`, `components/variable/`)。 - 新增 `PromptPreviewPanel` 组件和 `usePromptPreview` composable,提供提示词实时预览功能。 - 引入 `useContextManagement` composable,统一管理上下文状态和会话变量。 - 为上下文模式添加 E2E 测试。 - **类型与构建**: - 扩展 `ContextMode` 相关类型定义,更新组件 Props 和 Events 类型。 - 修复所有移动组件的相对导入路径和 `index.ts` 导出路径。 **主要问题修复** - **修复上下文-用户模式会话变量注入问题**: - **核心问题**: `testPromptWithType` 中错误地展开了 `ComputedRef` 对象而非其值,导致 `variables` 对象混入 Vue 响应式系统内部属性,Mustache 模板引擎无法正确访问嵌套的会话变量值。 - **修复内容**: - 优化 `App.vue` 变量合并逻辑,使用 `currentContextVariables.value` 获取实际值。 - `useContextManagement.ts` 新增 `updateContextVariable` 函数,统一管理会话变量。 - 简化 `TestAreaPanel.vue` 架构,移除 `userInputValues` 临时存储,改为单一数据源。 - `ContextUserWorkspace.vue` 添加 `variable-change` 事件转发。 - **影响范围**: 上下文-用户模式的变量替换功能、测试面板的会话变量输入、会话级变量管理和持久化。 - **测试验证**: 会话变量正确注入到测试请求,全局变量和预定义变量正常工作,变量合并优先级正确(全局 < 会话 < 预定义),Mustache 模板引擎正确替换占位符。 - **修复模型选择初始化竞态条件**: - **问题描述**: 模型选择初始化时可能出现竞态条件,导致在初始化完成前触发不必要的保存操作或回退逻辑错误。 - **修复内容**: - 引入 `isModelSelectionReady` 和 `isInitializing` 标志来精确跟踪初始化状态。 - 防止在初始化阶段的 `watch` 触发不必要的保存操作。 - 确保模型选择初始化完成后再执行回退逻辑。 - 调整相关代码格式(单引号转换为双引号)。
1 parent 2cb753e commit c8e06bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+8767
-4848
lines changed

packages/core/src/services/context/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
* 上下文服务相关常量定义
33
*/
44

5+
import type { ContextMode } from './types';
6+
57
// 存储键
68
export const CONTEXT_STORE_KEY = 'ctx:store' as const;
79

10+
// 默认上下文模式
11+
export const DEFAULT_CONTEXT_MODE: ContextMode = 'system' as const;
12+
813
// 预定义变量列表(与UI包保持一致)
914
// 这些变量名不允许在上下文变量覆盖中使用
1015
export const PREDEFINED_VARIABLES = [

packages/core/src/services/context/electron-proxy.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
11
/**
22
* Electron环境下ContextRepo的渲染进程代理
3-
*
3+
*
44
* 通过IPC与主进程的ContextRepo实例通信,
55
* 遵循项目现有的三层架构模式:Renderer代理 → Preload桥接 → 主进程IPC处理
66
*/
77

8-
import type { ContextRepo, ContextPackage, ContextBundle, ImportMode, ContextListItem, ImportResult } from './types';
8+
import type { ContextRepo, ContextPackage, ContextBundle, ImportMode, ContextListItem, ImportResult, ContextMode } from './types';
99
import { safeSerializeForIPC } from '../../utils/ipc-serialization';
1010

11+
// 为window.electronAPI提供完整的类型定义,以确保类型安全
12+
interface ElectronAPI {
13+
context: {
14+
list: () => Promise<ContextListItem[]>;
15+
getCurrentId: () => Promise<string>;
16+
setCurrentId: (id: string) => Promise<void>;
17+
get: (id: string) => Promise<ContextPackage>;
18+
create: (meta?: { title?: string; mode?: ContextMode }) => Promise<string>;
19+
duplicate: (id: string, options?: { mode?: ContextMode }) => Promise<string>;
20+
rename: (id: string, title: string) => Promise<void>;
21+
save: (ctx: ContextPackage) => Promise<void>;
22+
update: (id: string, patch: Partial<ContextPackage>) => Promise<void>;
23+
remove: (id: string) => Promise<void>;
24+
exportAll: () => Promise<ContextBundle>;
25+
importAll: (bundle: ContextBundle, mode: ImportMode) => Promise<ImportResult>;
26+
exportData: () => Promise<ContextBundle>;
27+
importData: (data: any) => Promise<void>;
28+
getDataType: () => Promise<string>;
29+
validateData: (data: any) => Promise<boolean>;
30+
};
31+
// 添加其他服务的定义以避免编译错误
32+
[key: string]: any;
33+
}
34+
35+
declare const window: {
36+
electronAPI: ElectronAPI;
37+
};
38+
1139
export class ElectronContextRepoProxy implements ContextRepo {
1240
private get api() {
1341
if (!window.electronAPI?.context) {
@@ -34,12 +62,12 @@ export class ElectronContextRepoProxy implements ContextRepo {
3462
}
3563

3664
// === 内容管理 ===
37-
async create(meta?: { title?: string }): Promise<string> {
65+
async create(meta?: { title?: string; mode?: import('./types').ContextMode }): Promise<string> {
3866
return this.api.create(meta);
3967
}
4068

41-
async duplicate(id: string): Promise<string> {
42-
return this.api.duplicate(id);
69+
async duplicate(id: string, options?: { mode?: import('./types').ContextMode }): Promise<string> {
70+
return this.api.duplicate(id, options);
4371
}
4472

4573
async rename(id: string, title: string): Promise<void> {

packages/core/src/services/context/repo.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import {
2424
PREDEFINED_VARIABLES,
2525
DEFAULT_CONTEXT_CONFIG,
2626
CONTEXT_STORE_VERSION,
27-
CONTEXT_UI_LABELS
27+
CONTEXT_UI_LABELS,
28+
DEFAULT_CONTEXT_MODE
2829
} from './constants';
2930

3031
/**
@@ -108,6 +109,7 @@ export class ContextRepoImpl implements ContextRepo {
108109
const defaultContext: ContextPackage = {
109110
id: DEFAULT_CONTEXT_CONFIG.id,
110111
title: DEFAULT_CONTEXT_CONFIG.title,
112+
mode: DEFAULT_CONTEXT_MODE,
111113
version: DEFAULT_CONTEXT_CONFIG.version,
112114
createdAt: now,
113115
updatedAt: now,
@@ -134,12 +136,29 @@ export class ContextRepoImpl implements ContextRepo {
134136

135137
try {
136138
const doc = JSON.parse(data) as ContextStoreDoc;
137-
139+
138140
// 基础验证
139141
if (!doc.currentId || !doc.contexts || typeof doc.contexts !== 'object') {
140142
throw new Error('Invalid document structure');
141143
}
142144

145+
// 迁移逻辑:为旧文档的上下文补写 mode 字段
146+
let migrated = false;
147+
for (const ctx of Object.values(doc.contexts)) {
148+
if (!ctx.mode) {
149+
ctx.mode = DEFAULT_CONTEXT_MODE;
150+
migrated = true;
151+
}
152+
}
153+
154+
// 如果有迁移,需要保存回存储
155+
if (migrated) {
156+
await this.storage.setItem(CONTEXT_STORE_KEY, JSON.stringify(doc));
157+
if (process.env.NODE_ENV === 'development') {
158+
console.log('[ContextRepo] Migrated contexts to add mode field');
159+
}
160+
}
161+
143162
// 确保currentId对应的上下文存在
144163
if (!doc.contexts[doc.currentId]) {
145164
// 修复:选择第一个可用的上下文
@@ -178,6 +197,7 @@ export class ContextRepoImpl implements ContextRepo {
178197
const defaultContext: ContextPackage = {
179198
id: DEFAULT_CONTEXT_CONFIG.id,
180199
title: DEFAULT_CONTEXT_CONFIG.title,
200+
mode: DEFAULT_CONTEXT_MODE,
181201
version: DEFAULT_CONTEXT_CONFIG.version,
182202
createdAt: now,
183203
updatedAt: now,
@@ -253,13 +273,14 @@ export class ContextRepoImpl implements ContextRepo {
253273
return { ...context };
254274
}
255275

256-
async create(meta?: { title?: string }): Promise<string> {
276+
async create(meta?: { title?: string; mode?: import('./types').ContextMode }): Promise<string> {
257277
const id = generateId();
258278
const now = getCurrentISOTime();
259-
279+
260280
const newContext: ContextPackage = {
261281
id,
262282
title: meta?.title || `${CONTEXT_UI_LABELS.DEFAULT_TITLE_TEMPLATE} ${new Date().toLocaleDateString()}`,
283+
mode: meta?.mode || DEFAULT_CONTEXT_MODE,
263284
version: DEFAULT_CONTEXT_CONFIG.version,
264285
createdAt: now,
265286
updatedAt: now,
@@ -279,18 +300,19 @@ export class ContextRepoImpl implements ContextRepo {
279300
return id;
280301
}
281302

282-
async duplicate(id: string): Promise<string> {
303+
async duplicate(id: string, options?: { mode?: import('./types').ContextMode }): Promise<string> {
283304
const originalCtx = await this.get(id); // 会抛出错误如果不存在
284305
const newId = generateId();
285306
const now = getCurrentISOTime();
286307

287308
// 复制时也需要清理变量
288309
const [sanitizedVariables] = sanitizeVariables(originalCtx.variables);
289-
310+
290311
const newContext: ContextPackage = {
291312
...originalCtx,
292313
id: newId,
293314
title: `${originalCtx.title} ${CONTEXT_UI_LABELS.DUPLICATE_SUFFIX}`,
315+
mode: options?.mode || originalCtx.mode || DEFAULT_CONTEXT_MODE,
294316
variables: sanitizedVariables,
295317
createdAt: now,
296318
updatedAt: now
@@ -327,6 +349,7 @@ export class ContextRepoImpl implements ContextRepo {
327349

328350
const contextToSave: ContextPackage = {
329351
...ctx,
352+
mode: ctx.mode || DEFAULT_CONTEXT_MODE,
330353
variables: sanitizedVariables,
331354
updatedAt: getCurrentISOTime()
332355
};
@@ -372,6 +395,7 @@ export class ContextRepoImpl implements ContextRepo {
372395

373396
// 合并安全的更新字段
374397
Object.assign(context, safeUpdate, {
398+
mode: patch.mode ?? context.mode ?? DEFAULT_CONTEXT_MODE,
375399
variables: sanitizedVariables || context.variables,
376400
updatedAt: getMonotonicISO(context.updatedAt)
377401
});
@@ -471,6 +495,7 @@ export class ContextRepoImpl implements ContextRepo {
471495

472496
const contextToImport: ContextPackage = {
473497
...ctx,
498+
mode: ctx.mode || DEFAULT_CONTEXT_MODE,
474499
variables: sanitizedVariables,
475500
updatedAt: now
476501
};
@@ -506,6 +531,7 @@ export class ContextRepoImpl implements ContextRepo {
506531
const contextToImport: ContextPackage = {
507532
...ctx,
508533
id: finalId,
534+
mode: ctx.mode || DEFAULT_CONTEXT_MODE,
509535
variables: sanitizedVariables,
510536
updatedAt: now
511537
};
@@ -535,13 +561,15 @@ export class ContextRepoImpl implements ContextRepo {
535561

536562
doc.contexts[ctx.id] = {
537563
...ctx,
564+
mode: ctx.mode || existingCtx.mode || DEFAULT_CONTEXT_MODE,
538565
variables: mergedVariables,
539566
updatedAt: now
540567
};
541568
} else {
542569
// 新ID:直接添加
543570
doc.contexts[ctx.id] = {
544571
...ctx,
572+
mode: ctx.mode || DEFAULT_CONTEXT_MODE,
545573
variables: sanitizedVariables,
546574
updatedAt: now
547575
};

packages/core/src/services/context/types.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
import type { IImportExportable } from '../../interfaces/import-export';
1212
import type { ConversationMessage, ToolDefinition } from '../prompt/types';
1313

14+
/**
15+
* 上下文模式
16+
* - system: 系统模式,保留完整的消息编辑能力
17+
* - user: 用户模式,聚焦于变量与工具管理
18+
*/
19+
export type ContextMode = 'system' | 'user';
20+
1421
/**
1522
* 上下文数据包
1623
* 包含一个完整上下文的所有信息:消息、变量覆盖、工具等
@@ -20,6 +27,8 @@ export interface ContextPackage {
2027
id: string;
2128
/** 上下文标题 */
2229
title: string;
30+
/** 上下文模式 */
31+
mode: ContextMode;
2332
/** 数据版本,用于未来兼容性 */
2433
version?: string;
2534
/** 创建时间(ISO字符串) */
@@ -136,18 +145,19 @@ export interface ContextRepo extends IImportExportable {
136145
// === 内容管理 ===
137146
/**
138147
* 创建新的上下文
139-
* @param meta 可选的元数据(标题等
148+
* @param meta 可选的元数据(标题、模式等
140149
* @returns 新创建的上下文ID
141150
*/
142-
create(meta?: { title?: string }): Promise<string>;
151+
create(meta?: { title?: string; mode?: ContextMode }): Promise<string>;
143152

144153
/**
145154
* 复制现有上下文
146155
* @param id 要复制的上下文ID
156+
* @param options 可选配置,包括模式
147157
* @returns 新创建的上下文ID
148158
* @throws 如果源ID不存在则抛出错误
149159
*/
150-
duplicate(id: string): Promise<string>;
160+
duplicate(id: string, options?: { mode?: ContextMode }): Promise<string>;
151161

152162
/**
153163
* 重命名上下文

0 commit comments

Comments
 (0)