@yh-ui/ai-sdk 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * YH-UI AI SDK - 文档加载器
3
+ *
4
+ * 支持 Markdown / 纯文本 / 结构化拆分。
5
+ * PDF、DOCX 通过接口预留,可由可选依赖或用户实现。
6
+ */
7
+ export interface LoadedDocument {
8
+ content: string;
9
+ metadata?: Record<string, unknown>;
10
+ source?: string;
11
+ }
12
+ export interface DocumentLoaderOptions {
13
+ /** 是否按段落/块拆分 */
14
+ split?: boolean;
15
+ /** 块大小(字符数) */
16
+ chunkSize?: number;
17
+ /** 块重叠(字符数) */
18
+ chunkOverlap?: number;
19
+ }
20
+ /**
21
+ * 文本加载器:直接使用字符串
22
+ */
23
+ export declare function createTextLoader(content: string, metadata?: Record<string, unknown>): LoadedDocument;
24
+ /**
25
+ * Markdown 加载器:按标题或段落拆分
26
+ */
27
+ export declare function loadMarkdown(markdown: string, options?: DocumentLoaderOptions): LoadedDocument[];
28
+ /**
29
+ * 通用分块:按固定大小拆分,带重叠
30
+ */
31
+ export declare function chunkText(text: string, options?: {
32
+ chunkSize?: number;
33
+ chunkOverlap?: number;
34
+ }): LoadedDocument[];
35
+ /**
36
+ * PDF 加载器接口(由用户或可选包实现)
37
+ * 可选依赖:pdf-parse / pdfjs-dist 等
38
+ */
39
+ export type PDFLoader = (input: string | ArrayBuffer | Buffer) => Promise<LoadedDocument[]>;
40
+ /**
41
+ * DOCX 加载器接口(由用户或可选包实现)
42
+ * 可选依赖:mammoth 等
43
+ */
44
+ export type DOCXLoader = (input: string | ArrayBuffer | Buffer) => Promise<LoadedDocument[]>;
45
+ /**
46
+ * 创建复合加载器:根据扩展名选择策略
47
+ */
48
+ export declare function createFileLoader(options: {
49
+ pdf?: PDFLoader;
50
+ docx?: DOCXLoader;
51
+ chunkSize?: number;
52
+ chunkOverlap?: number;
53
+ }): {
54
+ loadFromText(content: string): Promise<LoadedDocument[]>;
55
+ loadFromMarkdown(content: string): Promise<LoadedDocument[]>;
56
+ loadFromPDF(input: string | ArrayBuffer | Buffer): Promise<LoadedDocument[]>;
57
+ loadFromDOCX(input: string | ArrayBuffer | Buffer): Promise<LoadedDocument[]>;
58
+ };
@@ -0,0 +1,76 @@
1
+ export function createTextLoader(content, metadata) {
2
+ return { content: content.trim(), metadata };
3
+ }
4
+ export function loadMarkdown(markdown, options = {}) {
5
+ const chunkSize = options.chunkSize ?? 1e3;
6
+ const chunkOverlap = Math.min(options.chunkOverlap ?? 200, Math.floor(chunkSize * 0.5));
7
+ const { split = true } = options;
8
+ if (!split) {
9
+ return [{ content: markdown.trim(), metadata: { type: "markdown" } }];
10
+ }
11
+ const blocks = [];
12
+ const lines = markdown.split(/\r?\n/);
13
+ let current = "";
14
+ for (const line of lines) {
15
+ const isHeading = /^#{1,6}\s/.test(line);
16
+ if (isHeading && current.length >= chunkSize) {
17
+ if (current.trim()) blocks.push(current.trim());
18
+ current = line + "\n";
19
+ } else {
20
+ current += line + "\n";
21
+ if (current.length >= chunkSize) {
22
+ if (current.trim()) blocks.push(current.trim());
23
+ current = current.slice(-chunkOverlap);
24
+ }
25
+ }
26
+ }
27
+ if (current.trim()) blocks.push(current.trim());
28
+ return blocks.map((content, i) => ({
29
+ content,
30
+ metadata: { type: "markdown", index: i }
31
+ }));
32
+ }
33
+ export function chunkText(text, options = {}) {
34
+ const chunkSize = options.chunkSize ?? 800;
35
+ const chunkOverlap = Math.min(options.chunkOverlap ?? 100, Math.floor(chunkSize * 0.5));
36
+ const chunks = [];
37
+ let start = 0;
38
+ while (start < text.length) {
39
+ const end = Math.min(start + chunkSize, text.length);
40
+ let slice = text.slice(start, end);
41
+ if (end < text.length) {
42
+ const lastSpace = slice.lastIndexOf(" ");
43
+ if (lastSpace > chunkSize / 2) slice = slice.slice(0, lastSpace + 1);
44
+ }
45
+ if (slice.trim()) {
46
+ chunks.push({ content: slice.trim(), metadata: { index: chunks.length } });
47
+ }
48
+ const nextStart = start + slice.length - chunkOverlap;
49
+ start = nextStart > start ? nextStart : start + slice.length;
50
+ if (start >= text.length) break;
51
+ }
52
+ return chunks;
53
+ }
54
+ export function createFileLoader(options) {
55
+ const { pdf, docx, chunkSize = 800, chunkOverlap = 100 } = options;
56
+ return {
57
+ async loadFromText(content) {
58
+ return chunkText(content, { chunkSize, chunkOverlap });
59
+ },
60
+ async loadFromMarkdown(content) {
61
+ return loadMarkdown(content, { chunkSize, chunkOverlap });
62
+ },
63
+ async loadFromPDF(input) {
64
+ if (!pdf)
65
+ throw new Error("PDF loader not configured. Provide options.pdf or install a PDF library.");
66
+ return pdf(input);
67
+ },
68
+ async loadFromDOCX(input) {
69
+ if (!docx)
70
+ throw new Error(
71
+ "DOCX loader not configured. Provide options.docx or install a DOCX library."
72
+ );
73
+ return docx(input);
74
+ }
75
+ };
76
+ }
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MCPServer = void 0;
7
+ exports.createMCPServerHTTPHandler = createMCPServerHTTPHandler;
8
+ exports.useMCPServer = useMCPServer;
9
+ var _vue = require("vue");
10
+ class MCPServer {
11
+ config;
12
+ tools = /* @__PURE__ */new Map();
13
+ requestHandlers = /* @__PURE__ */new Map();
14
+ isRunning = false;
15
+ constructor(options) {
16
+ this.config = options.config;
17
+ if (options.tools) {
18
+ for (const tool of options.tools) {
19
+ this.tools.set(tool.name, tool);
20
+ }
21
+ }
22
+ this.registerRequestHandler("initialize", this.handleInitialize.bind(this));
23
+ this.registerRequestHandler("tools/list", this.handleToolsList.bind(this));
24
+ this.registerRequestHandler("tools/call", this.handleToolsCall.bind(this));
25
+ this.registerRequestHandler("ping", this.handlePing.bind(this));
26
+ options.onStart?.(this);
27
+ }
28
+ registerRequestHandler(method, handler) {
29
+ this.requestHandlers.set(method, handler);
30
+ }
31
+ generateId() {
32
+ return Math.random().toString(36).substring(2, 9);
33
+ }
34
+ // ── Request Handlers ─────────────────────────────────────────────────────
35
+ handleInitialize(params) {
36
+ const initParams = params;
37
+ return {
38
+ protocolVersion: initParams?.protocolVersion || "2024-11-05",
39
+ capabilities: {
40
+ tools: {}
41
+ },
42
+ serverInfo: {
43
+ name: this.config.name,
44
+ version: this.config.version
45
+ }
46
+ };
47
+ }
48
+ handleToolsList() {
49
+ const tools = Array.from(this.tools.values()).map(tool => ({
50
+ name: tool.name,
51
+ description: tool.description,
52
+ inputSchema: tool.inputSchema
53
+ }));
54
+ return {
55
+ tools
56
+ };
57
+ }
58
+ async handleToolsCall(params) {
59
+ const callParams = params;
60
+ if (!callParams?.name) {
61
+ throw new Error("Missing tool name");
62
+ }
63
+ const tool = this.tools.get(callParams.name);
64
+ if (!tool) {
65
+ throw new Error(`Tool not found: ${callParams.name}`);
66
+ }
67
+ try {
68
+ const result = await tool.execute(callParams.arguments || {});
69
+ return {
70
+ content: result
71
+ };
72
+ } catch (err) {
73
+ const errorMessage = err instanceof Error ? err.message : String(err);
74
+ return {
75
+ content: [{
76
+ type: "text",
77
+ text: errorMessage
78
+ }],
79
+ isError: true
80
+ };
81
+ }
82
+ }
83
+ handlePing() {
84
+ return {
85
+ pong: true
86
+ };
87
+ }
88
+ // ── Public API ───────────────────────────────────────────────────────────
89
+ /** Add a tool to the server */
90
+ addTool(tool) {
91
+ this.tools.set(tool.name, tool);
92
+ }
93
+ /** Remove a tool from the server */
94
+ removeTool(name) {
95
+ return this.tools.delete(name);
96
+ }
97
+ /** Get all tools */
98
+ getTools() {
99
+ return Array.from(this.tools.values());
100
+ }
101
+ /** Check if server is running */
102
+ getRunning() {
103
+ return this.isRunning;
104
+ }
105
+ /** Set running state */
106
+ setRunning(running) {
107
+ this.isRunning = running;
108
+ }
109
+ /** Handle a JSON-RPC request */
110
+ async handleRequest(request) {
111
+ const {
112
+ method,
113
+ params,
114
+ id
115
+ } = request;
116
+ const handler = this.requestHandlers.get(method);
117
+ if (!handler) {
118
+ return {
119
+ jsonrpc: "2.0",
120
+ id,
121
+ error: {
122
+ code: -32601,
123
+ // Method not found
124
+ message: `Method not found: ${method}`
125
+ }
126
+ };
127
+ }
128
+ try {
129
+ const result = await handler(params);
130
+ return {
131
+ jsonrpc: "2.0",
132
+ id,
133
+ result
134
+ };
135
+ } catch (err) {
136
+ const errorMessage = err instanceof Error ? err.message : String(err);
137
+ return {
138
+ jsonrpc: "2.0",
139
+ id,
140
+ error: {
141
+ code: -32e3,
142
+ message: errorMessage
143
+ }
144
+ };
145
+ }
146
+ }
147
+ /** Handle a batch of JSON-RPC requests */
148
+ async handleBatch(requests) {
149
+ return Promise.all(requests.map(req => this.handleRequest(req)));
150
+ }
151
+ /** Cleanup */
152
+ destroy() {
153
+ this.tools.clear();
154
+ this.requestHandlers.clear();
155
+ this.isRunning = false;
156
+ }
157
+ }
158
+ exports.MCPServer = MCPServer;
159
+ function useMCPServer(options) {
160
+ const config = {
161
+ name: options.name,
162
+ version: options.version,
163
+ capabilities: {
164
+ tools: true
165
+ }
166
+ };
167
+ const tools = (0, _vue.ref)(options.tools || []);
168
+ const isRunning = (0, _vue.ref)(false);
169
+ const server = new MCPServer({
170
+ config,
171
+ tools: options.tools,
172
+ onStart: () => {
173
+ isRunning.value = true;
174
+ },
175
+ onStop: () => {
176
+ isRunning.value = false;
177
+ }
178
+ });
179
+ const addTool = tool => {
180
+ server.addTool(tool);
181
+ tools.value = server.getTools();
182
+ options.onToolsChange?.(tools.value);
183
+ };
184
+ const removeTool = name => {
185
+ const result = server.removeTool(name);
186
+ tools.value = server.getTools();
187
+ options.onToolsChange?.(tools.value);
188
+ return result;
189
+ };
190
+ const handleRequest = async request => {
191
+ return server.handleRequest(request);
192
+ };
193
+ const start = () => {
194
+ server.setRunning(true);
195
+ isRunning.value = true;
196
+ };
197
+ const stop = () => {
198
+ server.setRunning(false);
199
+ isRunning.value = false;
200
+ server.destroy();
201
+ };
202
+ (0, _vue.onUnmounted)(() => {
203
+ stop();
204
+ });
205
+ return {
206
+ server,
207
+ config,
208
+ tools,
209
+ isRunning,
210
+ addTool,
211
+ removeTool,
212
+ handleRequest,
213
+ start,
214
+ stop
215
+ };
216
+ }
217
+ function createMCPServerHTTPHandler(options) {
218
+ const {
219
+ server,
220
+ handleRequest
221
+ } = useMCPServer(options);
222
+ return async function (request) {
223
+ if (request.method === "OPTIONS") {
224
+ return new Response(null, {
225
+ headers: {
226
+ "Access-Control-Allow-Origin": "*",
227
+ "Access-Control-Allow-Methods": "GET, POST",
228
+ "Access-Control-Allow-Headers": "Content-Type"
229
+ }
230
+ });
231
+ }
232
+ try {
233
+ const body = await request.json();
234
+ if (Array.isArray(body)) {
235
+ const responses = await server.handleBatch(body);
236
+ return new Response(JSON.stringify(responses), {
237
+ headers: {
238
+ "Content-Type": "application/json"
239
+ }
240
+ });
241
+ }
242
+ const response = await handleRequest(body);
243
+ return new Response(JSON.stringify(response), {
244
+ headers: {
245
+ "Content-Type": "application/json"
246
+ }
247
+ });
248
+ } catch (err) {
249
+ const errorMessage = err instanceof Error ? err.message : String(err);
250
+ return new Response(JSON.stringify({
251
+ jsonrpc: "2.0",
252
+ id: null,
253
+ error: {
254
+ code: -32603,
255
+ message: errorMessage
256
+ }
257
+ }), {
258
+ status: 500,
259
+ headers: {
260
+ "Content-Type": "application/json"
261
+ }
262
+ });
263
+ }
264
+ };
265
+ }
@@ -0,0 +1,186 @@
1
+ export interface MCPServerTool {
2
+ name: string;
3
+ description: string;
4
+ inputSchema: Record<string, unknown>;
5
+ /** Execute function - returns content array per MCP spec */
6
+ execute: (args: Record<string, unknown>) => Promise<MCPToolContent[]>;
7
+ }
8
+ export interface MCPToolContent {
9
+ type: 'text' | 'image' | 'resource';
10
+ text?: string;
11
+ data?: string;
12
+ mimeType?: string;
13
+ }
14
+ export interface MCPServerConfig {
15
+ /** Server name */
16
+ name: string;
17
+ /** Server version */
18
+ version: string;
19
+ /** Server capabilities */
20
+ capabilities?: {
21
+ tools?: boolean;
22
+ resources?: boolean;
23
+ prompts?: boolean;
24
+ };
25
+ }
26
+ export interface MCPServerOptions {
27
+ /** Server configuration */
28
+ config: MCPServerConfig;
29
+ /** Tools to expose */
30
+ tools?: MCPServerTool[];
31
+ /** Callback when server starts */
32
+ onStart?: (server: MCPServer) => void;
33
+ /** Callback when server stops */
34
+ onStop?: () => void;
35
+ /** Callback on error */
36
+ onError?: (error: Error) => void;
37
+ }
38
+ export type MCPServerTransport = 'http' | 'stdio';
39
+ export interface MCPHTTPHandler {
40
+ (request: MCPJSONRPCRequest): Promise<MCPJSONRPCResponse>;
41
+ }
42
+ export interface MCPJSONRPCRequest {
43
+ jsonrpc: '2.0';
44
+ id: number | string;
45
+ method: string;
46
+ params?: Record<string, unknown>;
47
+ }
48
+ export interface MCPJSONRPCResponse {
49
+ jsonrpc: '2.0';
50
+ id: number | string;
51
+ result?: unknown;
52
+ error?: {
53
+ code: number;
54
+ message: string;
55
+ data?: unknown;
56
+ };
57
+ }
58
+ export interface MCPJSONRPCNotification {
59
+ jsonrpc: '2.0';
60
+ method: string;
61
+ params?: Record<string, unknown>;
62
+ }
63
+ export declare class MCPServer {
64
+ readonly config: MCPServerConfig;
65
+ private tools;
66
+ private requestHandlers;
67
+ private isRunning;
68
+ constructor(options: MCPServerOptions);
69
+ private registerRequestHandler;
70
+ private generateId;
71
+ private handleInitialize;
72
+ private handleToolsList;
73
+ private handleToolsCall;
74
+ private handlePing;
75
+ /** Add a tool to the server */
76
+ addTool(tool: MCPServerTool): void;
77
+ /** Remove a tool from the server */
78
+ removeTool(name: string): boolean;
79
+ /** Get all tools */
80
+ getTools(): MCPServerTool[];
81
+ /** Check if server is running */
82
+ getRunning(): boolean;
83
+ /** Set running state */
84
+ setRunning(running: boolean): void;
85
+ /** Handle a JSON-RPC request */
86
+ handleRequest(request: MCPJSONRPCRequest): Promise<MCPJSONRPCResponse>;
87
+ /** Handle a batch of JSON-RPC requests */
88
+ handleBatch(requests: MCPJSONRPCRequest[]): Promise<MCPJSONRPCResponse[]>;
89
+ /** Cleanup */
90
+ destroy(): void;
91
+ }
92
+ export interface UseMCPServerOptions {
93
+ /** Server name */
94
+ name: string;
95
+ /** Server version */
96
+ version: string;
97
+ /** Initial tools */
98
+ tools?: MCPServerTool[];
99
+ /** Callback when tools change */
100
+ onToolsChange?: (tools: MCPServerTool[]) => void;
101
+ }
102
+ export interface UseMCPServerReturn {
103
+ /** Server instance */
104
+ server: MCPServer;
105
+ /** Server config */
106
+ config: MCPServerConfig;
107
+ /** Tools list (reactive) */
108
+ tools: {
109
+ value: MCPServerTool[];
110
+ };
111
+ /** Running state */
112
+ isRunning: {
113
+ value: boolean;
114
+ };
115
+ /** Add a tool */
116
+ addTool: (tool: MCPServerTool) => void;
117
+ /** Remove a tool */
118
+ removeTool: (name: string) => boolean;
119
+ /** Handle HTTP request */
120
+ handleRequest: (request: MCPJSONRPCRequest) => Promise<MCPJSONRPCResponse>;
121
+ /** Start server */
122
+ start: () => void;
123
+ /** Stop server */
124
+ stop: () => void;
125
+ }
126
+ /**
127
+ * useMCPServer - MCP Server Hook
128
+ *
129
+ * 将 AI 应用作为 MCP Server 暴露工具
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * const { server, addTool, tools } = useMCPServer({
134
+ * name: 'my-ai-server',
135
+ * version: '1.0.0',
136
+ * tools: [
137
+ * {
138
+ * name: 'get_weather',
139
+ * description: 'Get weather for a city',
140
+ * inputSchema: {
141
+ * type: 'object',
142
+ * properties: {
143
+ * city: { type: 'string', description: 'City name' }
144
+ * },
145
+ * required: ['city']
146
+ * },
147
+ * execute: async ({ city }) => {
148
+ * return [{ type: 'text', text: `Weather in ${city}: Sunny, 25°C` }]
149
+ * }
150
+ * }
151
+ * ]
152
+ * })
153
+ * ```
154
+ */
155
+ export declare function useMCPServer(options: UseMCPServerOptions): UseMCPServerReturn;
156
+ /**
157
+ * createMCPServerHTTPHandler - 创建 HTTP 处理函数
158
+ *
159
+ * 用于在 Express/Next.js API Route 中暴露 MCP Server
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * // Next.js API Route (app/api/mcp/route.ts)
164
+ * import { createMCPServerHTTPHandler } from '@yh-ui/ai-sdk/mcp'
165
+ *
166
+ * const handler = createMCPServerHTTPHandler({
167
+ * name: 'my-ai-server',
168
+ * version: '1.0.0',
169
+ * tools: [
170
+ * {
171
+ * name: 'search',
172
+ * description: 'Search for information',
173
+ * inputSchema: { type: 'object', properties: { query: { type: 'string' } } },
174
+ * execute: async ({ query }) => {
175
+ * // Search logic here
176
+ * return [{ type: 'text', text: `Results for: ${query}` }]
177
+ * }
178
+ * }
179
+ * ]
180
+ * })
181
+ *
182
+ * export const GET = handler
183
+ * export const POST = handler
184
+ * ```
185
+ */
186
+ export declare function createMCPServerHTTPHandler(options: UseMCPServerOptions): (request: Request) => Promise<Response>;