Browse Source

feat: 添加用户信息工具及其配置,更新 LLM 工具获取逻辑

feat/ai-sdk-v6-upgrade
npmrun 1 day ago
parent
commit
70c695d861
  1. BIN
      packages/drizzle-pkg/db.sqlite
  2. 2
      server/api/llm/chat/index.post.ts
  3. 27
      server/service/agent-tool/executors/user-info/config.ts
  4. 114
      server/service/agent-tool/executors/user-info/user-info.ts
  5. 14
      server/service/agent-tool/index.ts

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.

2
server/api/llm/chat/index.post.ts

@ -84,7 +84,7 @@ export default defineEventHandler(async (event) => {
const languageModel = resolveModel(provider, model.modelId);
const { tools, approvalConfig } = enableTools ? await getEnabledToolsForLlm() : { tools: undefined, approvalConfig: {} };
const { tools, approvalConfig } = enableTools ? await getEnabledToolsForLlm(user.id) : { tools: undefined, approvalConfig: {} };
const modelMessages = await convertToModelMessages(messages);

27
server/service/agent-tool/executors/user-info/config.ts

@ -0,0 +1,27 @@
import { z } from "zod";
export const userInfoConfigSchema = z.object({
includeEmail: z.boolean().default(true),
includeAvatar: z.boolean().default(true),
includeRole: z.boolean().default(true),
includeStatus: z.boolean().default(false),
includeCreatedAt: z.boolean().default(false),
});
export type UserInfoToolConfig = z.infer<typeof userInfoConfigSchema>;
export const DEFAULT_USER_INFO_CONFIG: UserInfoToolConfig = {
includeEmail: true,
includeAvatar: true,
includeRole: true,
includeStatus: false,
includeCreatedAt: false,
};
export function parseUserInfoConfig(raw: unknown): UserInfoToolConfig {
const parsed = userInfoConfigSchema.safeParse(raw);
if (!parsed.success) {
throw new Error(`Invalid user-info config: ${parsed.error.message}`);
}
return parsed.data;
}

114
server/service/agent-tool/executors/user-info/user-info.ts

@ -0,0 +1,114 @@
import { z } from "zod";
import type { JSONSchema7 } from "json-schema";
import { dbGlobal } from "drizzle-pkg/lib/db";
import { users } from "drizzle-pkg/lib/schema/auth";
import { eq } from "drizzle-orm";
import type { ToolExecutor, ToolContext, ToolResult } from "../../registry";
import type { UserInfoToolConfig } from "./config";
export const userInfoInputSchema = z.object({}).describe("无需参数,自动获取当前登录用户信息");
type UserInfoInput = z.infer<typeof userInfoInputSchema>;
export const userInfoExecutor: ToolExecutor<UserInfoToolConfig> = {
buildInputSchema(_config: UserInfoToolConfig): JSONSchema7 {
return {
type: "object",
properties: {},
description: "无需参数,自动根据当前会话获取用户信息",
};
},
buildDescription(config: UserInfoToolConfig): string {
const fields: string[] = [];
if (config.includeEmail) fields.push("邮箱");
if (config.includeAvatar) fields.push("头像");
if (config.includeRole) fields.push("角色");
if (config.includeStatus) fields.push("状态");
if (config.includeCreatedAt) fields.push("注册时间");
const fieldDesc = fields.length > 0 ? fields.join("、") : "基本信息";
return `获取当前登录用户信息(含${fieldDesc})。无需传入参数,自动从会话上下文中识别当前用户。`;
},
async execute(
input: unknown,
config: UserInfoToolConfig,
ctx: ToolContext,
): Promise<ToolResult> {
const start = Date.now();
const parsed = userInfoInputSchema.safeParse(input);
if (!parsed.success) {
return {
success: false,
data: null,
error: `输入参数校验失败: ${parsed.error.message}`,
metadata: { durationMs: Date.now() - start },
};
}
if (ctx.userId === null || ctx.userId === undefined) {
return {
success: false,
data: null,
error: "无法识别当前用户:会话上下文中缺少 userId。该工具需要在登录会话中调用。",
metadata: { durationMs: Date.now() - start },
};
}
try {
const rows = await dbGlobal
.select({
id: users.id,
username: users.username,
email: users.email,
nickname: users.nickname,
avatar: users.avatar,
role: users.role,
status: users.status,
createdAt: users.createdAt,
})
.from(users)
.where(eq(users.id, ctx.userId))
.limit(1);
const user = rows[0];
if (!user) {
return {
success: false,
data: null,
error: `未找到用户 (id=${ctx.userId})`,
metadata: { durationMs: Date.now() - start },
};
}
const data: Record<string, unknown> = {
id: user.id,
username: user.username,
nickname: user.nickname ?? null,
};
if (config.includeEmail) data.email = user.email ?? null;
if (config.includeAvatar) data.avatar = user.avatar ?? null;
if (config.includeRole) data.role = user.role;
if (config.includeStatus) data.status = user.status;
if (config.includeCreatedAt) {
data.createdAt = user.createdAt
? new Date(user.createdAt).toISOString()
: null;
}
return {
success: true,
data,
metadata: { durationMs: Date.now() - start },
};
} catch (e) {
return {
success: false,
data: null,
error: e instanceof Error ? e.message : String(e),
metadata: { durationMs: Date.now() - start },
};
}
},
};

14
server/service/agent-tool/index.ts

@ -21,6 +21,8 @@ import { parseJsonFormatterConfig, DEFAULT_JSON_FORMATTER_CONFIG } from "./execu
import { jsonFormatterExecutor, jsonFormatterInputSchema } from "./executors/json-formatter/json-formatter";
import { parseRegexTesterConfig, DEFAULT_REGEX_TESTER_CONFIG } from "./executors/regex-tester/config";
import { regexTesterExecutor, regexTesterInputSchema } from "./executors/regex-tester/regex-tester";
import { parseUserInfoConfig, DEFAULT_USER_INFO_CONFIG } from "./executors/user-info/config";
import { userInfoExecutor, userInfoInputSchema } from "./executors/user-info/user-info";
// ============ 工具类型注册表 ============
interface ToolTypeRegistration {
@ -73,6 +75,12 @@ const TOOL_TYPE_REGISTRY: Record<string, ToolTypeRegistration> = {
defaultConfig: DEFAULT_REGEX_TESTER_CONFIG,
zodSchema: regexTesterInputSchema,
},
"user-info": {
executor: userInfoExecutor,
parseConfig: parseUserInfoConfig,
defaultConfig: DEFAULT_USER_INFO_CONFIG,
zodSchema: userInfoInputSchema,
},
};
// 立即注册所有工具类型
@ -315,7 +323,7 @@ export async function getEnabledToolInfos(): Promise<EnabledToolInfo[]> {
return result;
}
export async function getEnabledToolsForLlm(): Promise<{
export async function getEnabledToolsForLlm(userId: number | null = null): Promise<{
tools: Record<string, ReturnType<typeof tool>>;
approvalConfig: Record<string, "user-approval" | "approved">;
}> {
@ -351,7 +359,7 @@ export async function getEnabledToolsForLlm(): Promise<{
},
}),
execute: async (input: unknown) => {
const execResult = await executeAgentTool(agentTool.id, input, null);
const execResult = await executeAgentTool(agentTool.id, input, userId);
if (!execResult.success) {
return `工具执行失败: ${execResult.error ?? "未知错误"}。请停止调用此工具,基于已有信息回答用户或告知用户此工具不可用。`;
}
@ -382,4 +390,6 @@ export { DEFAULT_JSON_FORMATTER_CONFIG } from "./executors/json-formatter/config
export type { JsonFormatterToolConfig } from "./executors/json-formatter/config";
export { DEFAULT_REGEX_TESTER_CONFIG } from "./executors/regex-tester/config";
export type { RegexTesterToolConfig } from "./executors/regex-tester/config";
export { DEFAULT_USER_INFO_CONFIG } from "./executors/user-info/config";
export type { UserInfoToolConfig } from "./executors/user-info/config";
export type { ToolExecutor, ToolContext, ToolResult } from "./registry";

Loading…
Cancel
Save