Skip to content

Commit c37eccb

Browse files
committed
feat(core, ui): 新增工具调用消息支持,增强类型安全
- 在消息角色中添加 'tool' 类型支持,完善 Function Calling 功能 - 扩展消息接口,添加 name、tool_calls、tool_call_id 字段 - 优化 PromptDataConverter,提升 LangFuse 数据转换的类型安全性 - 重构组件和 composables,将 any 类型替换为具体类型定义 - 更新国际化资源,添加 tool 角色相关翻译
1 parent 95e9bf2 commit c37eccb

Some content is hidden

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

60 files changed

+744
-506
lines changed

packages/core/src/services/llm/adapters/abstract-adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export abstract class AbstractTextProviderAdapter implements ITextProviderAdapte
144144
throw new RequestConfigError('Each message must have role and content')
145145
}
146146

147-
if (!['system', 'user', 'assistant'].includes(msg.role)) {
147+
if (!['system', 'user', 'assistant', 'tool'].includes(msg.role)) {
148148
throw new RequestConfigError(`Invalid message role: ${msg.role}`)
149149
}
150150

packages/core/src/services/llm/service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class LLMService implements ILLMService {
3535
if (!msg.role || !msg.content) {
3636
throw new RequestConfigError('消息格式无效: 缺少必要字段');
3737
}
38-
if (!['system', 'user', 'assistant'].includes(msg.role)) {
38+
if (!['system', 'user', 'assistant', 'tool'].includes(msg.role)) {
3939
throw new RequestConfigError(`不支持的消息类型: ${msg.role}`);
4040
}
4141
if (typeof msg.content !== 'string') {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,17 @@ export interface ToolDefinition {
132132
/**
133133
* 消息角色类型
134134
*/
135-
export type MessageRole = 'system' | 'user' | 'assistant';
135+
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
136136

137137
/**
138138
* 消息类型
139139
*/
140140
export interface Message {
141-
role: 'system' | 'user' | 'assistant';
141+
role: MessageRole;
142142
content: string;
143+
name?: string;
144+
tool_calls?: ToolCall[];
145+
tool_call_id?: string;
143146
}
144147

145148
/**

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,20 @@ export interface ToolDefinition {
2828
* 统一的消息结构
2929
*/
3030
export interface ConversationMessage {
31-
role: 'system' | 'user' | 'assistant';
31+
role: 'system' | 'user' | 'assistant' | 'tool';
3232
content: string; // 可包含变量语法 {{variableName}}
33+
/**
34+
* 函数调用名称(assistant消息)
35+
*/
36+
name?: string;
37+
/**
38+
* 函数调用列表(assistant消息)
39+
*/
40+
tool_calls?: ToolCall[];
41+
/**
42+
* 工具调用ID(tool消息)
43+
*/
44+
tool_call_id?: string;
3345
}
3446

3547
/**
@@ -124,4 +136,4 @@ export interface IPromptService {
124136
): Promise<void>;
125137
}
126138

127-
export type { StreamHandlers };
139+
export type { StreamHandlers };

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { z } from 'zod';
22
import { IImportExportable } from '../../interfaces/import-export';
33
import type { BuiltinTemplateLanguage } from './languageService';
4+
import type { ToolCall } from '../prompt/types';
45

56
/**
67
* 提示词元数据
@@ -19,8 +20,11 @@ export interface TemplateMetadata {
1920
* 消息模板定义
2021
*/
2122
export interface MessageTemplate {
22-
role: 'system' | 'user' | 'assistant';
23+
role: 'system' | 'user' | 'assistant' | 'tool';
2324
content: string;
25+
name?: string;
26+
tool_calls?: ToolCall[];
27+
tool_call_id?: string;
2428
}
2529

2630
/**
@@ -100,7 +104,7 @@ export interface ITemplateManager extends IImportExportable {
100104
* 消息模板验证Schema
101105
*/
102106
export const messageTemplateSchema = z.object({
103-
role: z.enum(['system', 'user', 'assistant']),
107+
role: z.enum(['system', 'user', 'assistant', 'tool']),
104108
content: z.string().min(1)
105109
});
106110

packages/ui/src/components/BasicTestMode.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ import { ref, computed, watch, nextTick } from 'vue'
149149
import { useI18n } from 'vue-i18n'
150150
import { NButton, NCard } from 'naive-ui'
151151
import { useToast } from '../composables/useToast'
152+
import type { AppServices } from '../types/services'
152153
import InputPanelUI from './InputPanel.vue'
153154
import ModelSelectUI from './ModelSelect.vue'
154155
import OutputDisplay from './OutputDisplay.vue'
@@ -157,7 +158,7 @@ const { t } = useI18n()
157158
const toast = useToast()
158159
159160
interface Props {
160-
services: any
161+
services: AppServices
161162
originalPrompt: string
162163
optimizedPrompt: string
163164
optimizationMode: 'system' | 'user'
@@ -203,7 +204,7 @@ const toggleCompareMode = () => {
203204
}
204205
205206
// 方法
206-
const ensureString = (value: any): string => {
207+
const ensureString = (value: string | number | boolean | null | undefined): string => {
207208
if (typeof value === 'string') return value
208209
if (value === null || value === undefined) return ''
209210
return String(value)

packages/ui/src/components/CategoryManager.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,10 @@ const handleConfirmDelete = async () => {
405405
message.success(t('favorites.categoryManager.deleteSuccess'));
406406
await loadCategories();
407407
emit('category-updated');
408-
} catch (error: any) {
408+
} catch (error) {
409409
console.error('删除分类失败:', error);
410-
message.error(`${t('favorites.categoryManager.deleteFailed')}: ${error.message || '未知错误'}`);
410+
const errorMessage = error instanceof Error ? error.message : '未知错误';
411+
message.error(`${t('favorites.categoryManager.deleteFailed')}: ${errorMessage}`);
411412
} finally {
412413
deleteDialogVisible.value = false;
413414
deletingCategory.value = null;
@@ -454,9 +455,10 @@ const handleSaveCategory = async () => {
454455
editDialogVisible.value = false;
455456
await loadCategories();
456457
emit('category-updated');
457-
} catch (error: any) {
458+
} catch (error) {
458459
console.error('保存分类失败:', error);
459-
message.error(`${t('favorites.categoryManager.saveFailed')}: ${error.message || '未知错误'}`);
460+
const errorMessage = error instanceof Error ? error.message : '未知错误';
461+
message.error(`${t('favorites.categoryManager.saveFailed')}: ${errorMessage}`);
460462
} finally {
461463
saving.value = false;
462464
}
@@ -497,9 +499,10 @@ const loadCategories = async () => {
497499
498500
try {
499501
categories.value = await servicesValue.favoriteManager.getCategories();
500-
} catch (error: any) {
502+
} catch (error) {
501503
console.error('加载分类失败:', error);
502-
message.error(`${t('favorites.categoryManager.loadFailed')}: ${error.message || '未知错误'}`);
504+
const errorMessage = error instanceof Error ? error.message : '未知错误';
505+
message.error(`${t('favorites.categoryManager.loadFailed')}: ${errorMessage}`);
503506
}
504507
};
505508

packages/ui/src/components/CategoryTreeSelect.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ const loadCategories = async () => {
125125
126126
try {
127127
categories.value = await servicesValue.favoriteManager.getCategories();
128-
} catch (error: any) {
128+
} catch (error) {
129129
console.error('加载分类失败:', error);
130130
}
131131
};

0 commit comments

Comments
 (0)