diff --git a/agent/package.json b/agent/package.json index 1f18fa1551b..23d2a22a551 100644 --- a/agent/package.json +++ b/agent/package.json @@ -38,6 +38,7 @@ "@elizaos/plugin-conflux": "workspace:*", "@elizaos/plugin-evm": "workspace:*", "@elizaos/plugin-flow": "workspace:*", + "@elizaos/plugin-gitbook": "workspace:*", "@elizaos/plugin-story": "workspace:*", "@elizaos/plugin-goat": "workspace:*", "@elizaos/plugin-icp": "workspace:*", @@ -64,3 +65,4 @@ "tsup": "8.3.5" } } + diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 6786bb99f9e..26bc01ee45a 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -783,6 +783,13 @@ export type Character = { shouldIgnoreBotMessages?: boolean; shouldIgnoreDirectMessages?: boolean; }; + gitbook?: { + keywords?: { + projectTerms?: string[]; + generalQueries?: string[]; + }; + documentTriggers?: string[]; + }; }; /** Writing style guides */ diff --git a/packages/plugin-gitbook/package.json b/packages/plugin-gitbook/package.json new file mode 100644 index 00000000000..5658dd52883 --- /dev/null +++ b/packages/plugin-gitbook/package.json @@ -0,0 +1,25 @@ +{ + "name": "@elizaos/plugin-gitbook", + "version": "0.1.0", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "files": [ + "dist" + ], + "dependencies": { + "@elizaos/core": "workspace:*", + "tsup": "8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "test": "vitest" + } +} diff --git a/packages/plugin-gitbook/src/index.ts b/packages/plugin-gitbook/src/index.ts new file mode 100644 index 00000000000..c44002e055f --- /dev/null +++ b/packages/plugin-gitbook/src/index.ts @@ -0,0 +1,14 @@ +import { Plugin } from "@elizaos/core"; +import { gitbookProvider } from "./providers/gitbook"; + +export const gitbookPlugin: Plugin = { + name: "GitBook Documentation", + description: "Plugin for querying GitBook documentation", + actions: [], + providers: [gitbookProvider], + evaluators: [] +}; + +export default gitbookPlugin; + +export * from './types'; diff --git a/packages/plugin-gitbook/src/providers/gitbook.ts b/packages/plugin-gitbook/src/providers/gitbook.ts new file mode 100644 index 00000000000..2c42aff62b0 --- /dev/null +++ b/packages/plugin-gitbook/src/providers/gitbook.ts @@ -0,0 +1,112 @@ +import { Provider, IAgentRuntime, Memory, State, elizaLogger } from "@elizaos/core"; +import { GitBookResponse, GitBookClientConfig } from '../types'; + +function cleanText(text: string): string { + const cleaned = text + .replace(/<@!?\d+>/g, '') // Discord mentions + .replace(/<#\d+>/g, '') // Discord channels + .replace(/<@&\d+>/g, '') // Discord roles + .replace(/(?:^|\s)@[\w_]+/g, '') // Platform mentions + .trim(); + + return cleaned; +} + +async function validateQuery(runtime: IAgentRuntime, text: string): Promise { + // Default general queries - everything else comes from config + let keywords = { + generalQueries: [ + 'how', 'what', 'where', 'explain', 'show', 'tell', + 'can', 'does', 'is', 'are', 'will', 'why', + 'benefits', 'features', 'cost', 'price', + 'use', 'using', 'work', 'access', 'get' + ] + }; + + try { + const gitbookConfig = runtime.character.clientConfig?.gitbook as GitBookClientConfig; + + // Get project terms and document triggers from config + const projectTerms = gitbookConfig?.keywords?.projectTerms || []; + const documentTriggers = gitbookConfig?.documentTriggers || []; + + // Merge any additional general queries from config + if (gitbookConfig?.keywords?.generalQueries) { + keywords.generalQueries = [ + ...keywords.generalQueries, + ...gitbookConfig.keywords.generalQueries + ]; + } + + const containsAnyWord = (text: string, words: string[] = []) => { + return words.length === 0 || words.some(word => { + if (word.includes(' ')) { + return text.includes(word.toLowerCase()); + } + const regex = new RegExp(`\\b${word}\\b`, 'i'); + return regex.test(text); + }); + }; + + const hasProjectTerm = containsAnyWord(text, projectTerms); + const hasDocTrigger = containsAnyWord(text, documentTriggers); + const hasGeneralQuery = containsAnyWord(text, keywords.generalQueries); + + const isValid = hasProjectTerm || hasDocTrigger || hasGeneralQuery; + + elizaLogger.info(`✅ Is GitBook Validation Result: ${isValid}`) + return isValid; + + } catch (error) { + elizaLogger.warn(`❌ Error in GitBook validation:\n${error}`) + return false; + } +} + +export const gitbookProvider: Provider = { + get: async (runtime: IAgentRuntime, message: Memory, _state?: State): Promise => { + try { + const spaceId = runtime.getSetting("GITBOOK_SPACE_ID"); + if (!spaceId) { + elizaLogger.error('⚠️ GitBook Space ID not configured') + return ""; + } + + const text = message.content.text.toLowerCase().trim(); + const isValidQuery = await validateQuery(runtime, text); + + if (!isValidQuery) { + elizaLogger.info('⚠️ GitBook Query validation failed') + return ""; + } + + const cleanedQuery = cleanText(message.content.text); + + const response = await fetch( + `https://api.gitbook.com/v1/spaces/${spaceId}/search/ask`, + { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + query: cleanedQuery, + variables: {} + }) + } + ); + + if (!response.ok) { + console.error('❌ GitBook API error:', response.status); + return ""; + } + + const result: GitBookResponse = await response.json(); + + return result.answer?.text || ""; + } catch (error) { + console.error("❌ Error in GitBook provider:", error); + return ""; + } + } +}; diff --git a/packages/plugin-gitbook/src/types.ts b/packages/plugin-gitbook/src/types.ts new file mode 100644 index 00000000000..e336c936a57 --- /dev/null +++ b/packages/plugin-gitbook/src/types.ts @@ -0,0 +1,18 @@ +// GitBook API response type +export interface GitBookResponse { + answer?: { + text: string; + }; + error?: string; +} + +// Client configuration in character.json (all optional) +export interface GitBookKeywords { + projectTerms?: string[]; + generalQueries?: string[]; +} + +export interface GitBookClientConfig { + keywords?: GitBookKeywords; + documentTriggers?: string[]; +} \ No newline at end of file diff --git a/packages/plugin-gitbook/tsconfig.json b/packages/plugin-gitbook/tsconfig.json new file mode 100644 index 00000000000..7251ebee37d --- /dev/null +++ b/packages/plugin-gitbook/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "types": [ + "node" + ] + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/packages/plugin-gitbook/tsup.config.ts b/packages/plugin-gitbook/tsup.config.ts new file mode 100644 index 00000000000..b3cda18ce73 --- /dev/null +++ b/packages/plugin-gitbook/tsup.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + external: [ + "@elizaos/core" + ], +});