5 changed files with 154 additions and 3 deletions
Binary file not shown.
@ -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; |
|||
} |
|||
@ -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 }, |
|||
}; |
|||
} |
|||
}, |
|||
}; |
|||
Loading…
Reference in new issue