@redonvn/redai-openapi-router 0.1.1
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.
- package/README.md +11 -0
- package/data/modules/agent.json +12303 -0
- package/data/modules/marketing.json +39015 -0
- package/data/modules/models.json +4225 -0
- package/data/modules/user.json +3965 -0
- package/data/modules/workflow.json +8253 -0
- package/data/sitemap.json +268 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +795 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +47 -0
- package/package.json +55 -0
- package/skills/redai-openapi-router/SKILL.md +28 -0
- package/skills/redai-openapi-router/agents/openai.yaml +7 -0
- package/tool-catalog.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts","../../redai-agent-sdk/src/client.ts","../tool-catalog.json"],"sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n RedaiAgentClient,\n RedaiAgentError,\n type ToolExecutionInput\n} from \"@redonvn/redai-agent-sdk\";\nimport toolCatalog from \"./tool-catalog.json\";\n\ntype PluginRuntimeConfig = {\n baseUrl?: string;\n bearerToken?: string;\n apiKey?: string;\n apiKeyHeader?: string;\n defaultHeaders?: Record<string, string>;\n timeoutMs?: number;\n workspaceId?: string;\n baseId?: string;\n authStorePath?: string;\n};\n\ntype ToolResult = { content: Array<{ type: \"text\"; text: string }> };\n\ntype OpenClawApiLike = {\n config?: {\n plugins?: {\n entries?: Record<string, { config?: PluginRuntimeConfig }>;\n };\n };\n registerTool: (\n definition: {\n name: string;\n description: string;\n parameters: unknown;\n execute: (id: string, params: unknown) => Promise<ToolResult>;\n },\n options?: { optional?: boolean }\n ) => void;\n};\n\ntype RouterCatalog = {\n catalogVersion: string;\n generatedAt: string;\n modules: SitemapModule[];\n};\n\ntype SitemapModule = {\n id: string;\n pluginId: string;\n title: string;\n summary: string;\n whenToUse: string[];\n whenNotToUse: string[];\n keywords: string[];\n featureGroups: string[];\n topOperations: string[];\n operationCount: number;\n moduleFile: string;\n};\n\ntype ModuleDoc = {\n id: string;\n pluginId: string;\n pluginName: string;\n title: string;\n summary: string;\n purpose: string;\n whenToUse: string[];\n whenNotToUse: string[];\n keywords: string[];\n commonTasks: Array<{ id: string; title: string; operationIds: string[] }>;\n featureGroups: Array<{ id: string; title: string; summary: string; keywords: string[]; operationIds: string[] }>;\n operations: OperationDoc[];\n};\n\ntype OperationDoc = {\n id: string;\n moduleId: string;\n featureGroupId: string;\n toolName: string;\n operationId: string;\n title: string;\n summary: string;\n businessMeaning: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n path: string;\n tags: string[];\n keywords: string[];\n whenToUse: string[];\n whenNotToUse: string[];\n riskLevel: \"safe\" | \"confirm_required\" | \"destructive\" | \"costly\";\n confirmationRequired: boolean;\n requiresAuth: boolean;\n parameterSummary: {\n requiredFields: string[];\n topLevelRequired: string[];\n };\n parameterSchema: unknown;\n};\n\ntype RedaiAuthEntry = {\n telegramUserId: string;\n bearerToken: string;\n workspaceId: string;\n baseId?: string | null;\n savedAt: string;\n lastValidatedAt: string | null;\n status: \"active\" | \"invalid\";\n};\n\ntype RedaiAuthStore = {\n version: 1;\n users: Record<string, RedaiAuthEntry>;\n};\n\nconst typedToolCatalog = toolCatalog as {\n pluginId: string;\n optional?: boolean;\n};\n\nconst DEFAULT_AUTH_STORE_PATH =\n \"C:\\\\Users\\\\Acer\\\\.openclaw\\\\workspace-nhan-vien-redai\\\\auth\\\\redai-auth.json\";\n\nconst currentDir = path.dirname(fileURLToPath(import.meta.url));\nconst dataRoot = path.resolve(currentDir, \"..\", \"data\");\nconst sitemapPath = path.join(dataRoot, \"sitemap.json\");\nconst moduleCache = new Map<string, ModuleDoc>();\nlet sitemapCache: RouterCatalog | null = null;\n\nconst formatToolResult = (payload: unknown): ToolResult => ({\n content: [\n {\n type: \"text\",\n text: typeof payload === \"string\" ? payload : JSON.stringify(payload, null, 2)\n }\n ]\n});\n\nconst resolvePluginConfig = (api: OpenClawApiLike): PluginRuntimeConfig =>\n api.config?.plugins?.entries?.[typedToolCatalog.pluginId]?.config ?? {};\n\nconst ensureStoreDirectory = async (storePath: string) => {\n await mkdir(path.dirname(storePath), { recursive: true });\n};\n\nconst getAuthStorePath = (runtimeConfig: PluginRuntimeConfig) =>\n runtimeConfig.authStorePath?.trim() || DEFAULT_AUTH_STORE_PATH;\n\nconst loadAuthStore = async (runtimeConfig: PluginRuntimeConfig): Promise<RedaiAuthStore> => {\n const storePath = getAuthStorePath(runtimeConfig);\n try {\n const raw = await readFile(storePath, \"utf8\");\n const parsed = JSON.parse(raw) as RedaiAuthStore;\n return { version: 1, users: parsed?.users ?? {} };\n } catch (error: unknown) {\n const maybeNodeError = error as NodeJS.ErrnoException;\n if (maybeNodeError?.code === \"ENOENT\") {\n await ensureStoreDirectory(storePath);\n await writeFile(storePath, JSON.stringify({ version: 1, users: {} }, null, 2), \"utf8\");\n return { version: 1, users: {} };\n }\n throw error;\n }\n};\n\nconst getAuthStoreEntry = async (runtimeConfig: PluginRuntimeConfig, telegramUserId: string) => {\n const store = await loadAuthStore(runtimeConfig);\n return store.users[telegramUserId] ?? null;\n};\n\nconst withRedaiAuth = (\n runtimeConfig: PluginRuntimeConfig,\n auth: Pick<RedaiAuthEntry, \"bearerToken\" | \"workspaceId\" | \"baseId\">\n): PluginRuntimeConfig => {\n const defaultHeaders = {\n ...(runtimeConfig.defaultHeaders ?? {}),\n \"x-workspace-id\": auth.workspaceId\n } as Record<string, string>;\n\n if (auth.baseId) {\n defaultHeaders[\"x-base-id\"] = auth.baseId;\n } else {\n delete defaultHeaders[\"x-base-id\"];\n }\n\n return {\n ...runtimeConfig,\n bearerToken: auth.bearerToken,\n apiKey: undefined,\n apiKeyHeader: undefined,\n defaultHeaders,\n workspaceId: auth.workspaceId,\n baseId: auth.baseId ?? undefined\n };\n};\n\nconst resolveUserRuntimeConfig = async (api: OpenClawApiLike, telegramUserId: string) => {\n const runtimeConfig = resolvePluginConfig(api);\n const authEntry = await getAuthStoreEntry(runtimeConfig, telegramUserId);\n if (!authEntry || authEntry.status !== \"active\") {\n return null;\n }\n return {\n runtimeConfig,\n scopedConfig: withRedaiAuth(runtimeConfig, authEntry)\n };\n};\n\nconst authRequiredResult = (telegramUserId: string) =>\n formatToolResult({\n ok: false,\n status: 401,\n statusText: \"AUTH_REQUIRED\",\n data: {\n message:\n \"Ban chua dang nhap RedAI auth hop le. Hay dung /login <bearerToken> <workspaceId> [baseId] trong DM truoc khi thao tac nghiep vu.\",\n telegramUserId\n }\n });\n\nconst normalizeText = (value: string) =>\n value\n .normalize(\"NFKD\")\n .replace(/[^\\w\\s-]/g, \" \")\n .toLowerCase();\n\nconst tokenize = (value: string) =>\n normalizeText(value)\n .split(/\\s+/)\n .map((item) => item.trim())\n .filter(Boolean);\n\ntype QueryIntent = {\n wantsRead: boolean;\n wantsMutation: boolean;\n wantsDestructive: boolean;\n wantsBulk: boolean;\n wantsExport: boolean;\n mentionsExactOperation: boolean;\n};\n\nconst READ_HINTS = [\n \"xem\",\n \"liet\",\n \"lietke\",\n \"list\",\n \"get\",\n \"chi\",\n \"tiet\",\n \"detail\",\n \"thong\",\n \"tin\",\n \"tim\",\n \"kiem\",\n \"search\",\n \"find\",\n \"tra\",\n \"cuu\",\n \"kiemtra\",\n \"check\",\n \"doc\",\n \"read\",\n \"preview\"\n];\n\nconst MUTATION_HINTS = [\n \"tao\",\n \"them\",\n \"cap\",\n \"nhat\",\n \"update\",\n \"create\",\n \"edit\",\n \"sua\",\n \"run\",\n \"execute\",\n \"gui\",\n \"send\",\n \"pause\",\n \"resume\",\n \"sync\",\n \"train\",\n \"fine\",\n \"tuning\"\n];\n\nconst DESTRUCTIVE_HINTS = [\n \"xoa\",\n \"delete\",\n \"remove\",\n \"huy\",\n \"cancel\",\n \"reset\",\n \"clear\",\n \"drop\"\n];\n\nconst BULK_HINTS = [\"hangloat\", \"bulk\", \"batch\", \"nhieu\", \"tatca\", \"all\"];\n\nconst EXPORT_HINTS = [\"export\", \"tai\", \"file\", \"csv\", \"excel\", \"download\"];\n\nconst inferQueryIntent = (query: string, queryTokens: string[]): QueryIntent => {\n const normalizedQuery = normalizeText(query);\n const hasAnyHint = (hints: string[]) =>\n hints.some((hint) => normalizedQuery.includes(normalizeText(hint)) || queryTokens.includes(normalizeText(hint)));\n\n return {\n wantsRead: hasAnyHint(READ_HINTS),\n wantsMutation: hasAnyHint(MUTATION_HINTS),\n wantsDestructive: hasAnyHint(DESTRUCTIVE_HINTS),\n wantsBulk: hasAnyHint(BULK_HINTS),\n wantsExport: hasAnyHint(EXPORT_HINTS),\n mentionsExactOperation: normalizedQuery.includes(\":\") || normalizedQuery.includes(\"_v1\")\n };\n};\n\nconst getSitemap = async (): Promise<RouterCatalog> => {\n if (!sitemapCache) {\n sitemapCache = JSON.parse(await readFile(sitemapPath, \"utf8\")) as RouterCatalog;\n }\n return sitemapCache;\n};\n\nconst getModuleDoc = async (moduleId: string): Promise<ModuleDoc | null> => {\n if (moduleCache.has(moduleId)) {\n return moduleCache.get(moduleId) ?? null;\n }\n const sitemap = await getSitemap();\n const entry = sitemap.modules.find((item) => item.id === moduleId);\n if (!entry) {\n return null;\n }\n const parsed = JSON.parse(await readFile(path.join(dataRoot, entry.moduleFile), \"utf8\")) as ModuleDoc;\n moduleCache.set(moduleId, parsed);\n return parsed;\n};\n\nconst findOperation = async (operationId: string): Promise<OperationDoc | null> => {\n const moduleId = operationId.split(\":\")[0];\n const moduleDoc = await getModuleDoc(moduleId);\n return moduleDoc?.operations.find((item) => item.id === operationId) ?? null;\n};\n\nconst scoreOperation = (\n queryTokens: string[],\n intent: QueryIntent,\n requestedModuleId: string | undefined,\n moduleDoc: ModuleDoc,\n operation: OperationDoc\n) => {\n let score = 0;\n const exactQuery = queryTokens.join(\" \");\n const opJoined = normalizeText(\n [\n operation.id,\n operation.operationId,\n operation.title,\n operation.summary,\n operation.businessMeaning,\n ...operation.tags,\n ...operation.keywords\n ].join(\" \")\n );\n const moduleJoined = normalizeText(\n [moduleDoc.id, moduleDoc.title, moduleDoc.summary, moduleDoc.purpose, ...moduleDoc.keywords].join(\" \")\n );\n\n if (requestedModuleId && moduleDoc.id === requestedModuleId) {\n score += 20;\n }\n if (normalizeText(operation.id) === exactQuery || normalizeText(operation.operationId) === exactQuery) {\n score += 100;\n }\n for (const token of queryTokens) {\n if (normalizeText(operation.operationId).includes(token)) {\n score += 20;\n }\n if (opJoined.includes(token)) {\n score += 12;\n }\n if (moduleJoined.includes(token)) {\n score += 6;\n }\n }\n\n if (operation.method === \"GET\") {\n score += 4;\n } else {\n score -= 2;\n }\n\n if (operation.riskLevel === \"safe\") {\n score += 8;\n }\n if (operation.riskLevel === \"confirm_required\") {\n score -= 8;\n }\n if (operation.riskLevel === \"costly\") {\n score -= intent.wantsMutation ? 6 : 18;\n }\n if (operation.riskLevel === \"destructive\") {\n score -= intent.wantsDestructive ? 10 : 32;\n }\n\n const opText = normalizeText(\n [\n operation.id,\n operation.operationId,\n operation.title,\n operation.summary,\n operation.businessMeaning,\n ...operation.whenToUse,\n ...operation.whenNotToUse,\n ...operation.keywords\n ].join(\" \")\n );\n\n if (intent.wantsRead) {\n if (operation.method === \"GET\") {\n score += 10;\n }\n if (operation.riskLevel === \"safe\") {\n score += 6;\n }\n }\n\n if (intent.wantsMutation && operation.method !== \"GET\") {\n score += 10;\n }\n\n if (intent.wantsDestructive && /(delete|remove|cancel|reset|bulkremove|bulkdelete|destroy|xoa|huy)/.test(opText)) {\n score += 18;\n }\n\n if (intent.wantsBulk && /(bulk|batch|hang loat|tat ca|all)/.test(opText)) {\n score += 12;\n }\n\n if (intent.wantsExport && /(export|download|csv|excel|file)/.test(opText)) {\n score += 16;\n }\n\n if (!intent.wantsMutation && !intent.wantsDestructive && operation.method !== \"GET\") {\n score -= 10;\n }\n\n if (!intent.wantsBulk && /(bulk|batch)/.test(opText)) {\n score -= 10;\n }\n\n if (!intent.wantsExport && /(export|download)/.test(opText)) {\n score -= 10;\n }\n\n if (!intent.mentionsExactOperation && operation.confirmationRequired) {\n score -= 8;\n }\n\n return score;\n};\n\nconst summarizeOperation = (operation: OperationDoc) => ({\n id: operation.id,\n title: operation.title,\n summary: operation.summary,\n method: operation.method,\n path: operation.path,\n riskLevel: operation.riskLevel,\n confirmationRequired: operation.confirmationRequired,\n featureGroupId: operation.featureGroupId\n});\n\nconst buildMatchReasons = (queryTokens: string[], intent: QueryIntent, moduleDoc: ModuleDoc, operation: OperationDoc) => {\n const reasons: string[] = [];\n const normalizedOperation = normalizeText(\n [operation.operationId, operation.title, ...operation.tags, ...operation.keywords].join(\" \")\n );\n const normalizedModule = normalizeText([moduleDoc.title, ...moduleDoc.keywords].join(\" \"));\n\n if (queryTokens.some((token) => normalizeText(operation.operationId).includes(token))) {\n reasons.push(\"operation-id\");\n }\n if (queryTokens.some((token) => normalizedOperation.includes(token))) {\n reasons.push(\"keyword\");\n }\n if (queryTokens.some((token) => normalizedModule.includes(token))) {\n reasons.push(\"module\");\n }\n if (intent.wantsRead && operation.method === \"GET\") {\n reasons.push(\"read-safe\");\n }\n if (intent.wantsMutation && operation.method !== \"GET\") {\n reasons.push(\"write-intent\");\n }\n if (intent.wantsDestructive && operation.riskLevel === \"destructive\") {\n reasons.push(\"destructive-intent\");\n }\n if (intent.wantsExport && /(export|download)/.test(normalizeText(operation.id))) {\n reasons.push(\"export-intent\");\n }\n\n return reasons.length > 0 ? reasons : [operation.tags[0] ?? moduleDoc.title];\n};\n\nconst hasHeadersSection = (schema: unknown): boolean => {\n const objectSchema = schema as { properties?: Record<string, unknown> } | undefined;\n return Boolean(objectSchema?.properties?.headers);\n};\n\nconst mergeTenantHeaders = (\n schema: unknown,\n inputHeaders: Record<string, unknown> | undefined,\n runtimeConfig: PluginRuntimeConfig\n): Record<string, string> | undefined => {\n const entries = Object.entries(inputHeaders ?? {})\n .filter(([, value]) => value !== undefined && value !== null && value !== \"\")\n .map(([key, value]) => [key, String(value)] as const);\n\n if (hasHeadersSection(schema)) {\n if (runtimeConfig.workspaceId && !entries.some(([key]) => key.toLowerCase() === \"x-workspace-id\")) {\n entries.push([\"x-workspace-id\", runtimeConfig.workspaceId]);\n }\n if (runtimeConfig.baseId && !entries.some(([key]) => key.toLowerCase() === \"x-base-id\")) {\n entries.push([\"x-base-id\", runtimeConfig.baseId]);\n }\n }\n\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n};\n\nconst executeOperation = async (\n runtimeConfig: PluginRuntimeConfig,\n operation: OperationDoc,\n rawArgs: unknown\n) => {\n const client = new RedaiAgentClient({\n ...runtimeConfig,\n baseUrl: runtimeConfig.baseUrl\n });\n const args = (rawArgs ?? {}) as ToolExecutionInput & { headers?: Record<string, unknown> };\n\n return client.executeTool(\n { method: operation.method, path: operation.path },\n {\n path: args.path,\n query: args.query,\n body: args.body,\n headers: mergeTenantHeaders(operation.parameterSchema, args.headers, runtimeConfig)\n }\n );\n};\n\nexport default function register(api: OpenClawApiLike): void {\n api.registerTool(\n {\n name: \"redai_router_list_modules\",\n description: \"Liet ke cac module RedAI co san trong router.\",\n parameters: { type: \"object\", properties: {}, additionalProperties: false },\n execute: async () => {\n const sitemap = await getSitemap();\n return formatToolResult({\n catalogVersion: sitemap.catalogVersion,\n generatedAt: sitemap.generatedAt,\n modules: sitemap.modules.map((item) => ({\n id: item.id,\n title: item.title,\n summary: item.summary,\n whenToUse: item.whenToUse,\n whenNotToUse: item.whenNotToUse,\n operationCount: item.operationCount,\n topOperations: item.topOperations\n }))\n });\n }\n },\n { optional: typedToolCatalog.optional ?? true }\n );\n\n api.registerTool(\n {\n name: \"redai_router_search\",\n description: \"Tim operation phu hop theo y nghia nghiep vu, module va tu khoa.\",\n parameters: {\n type: \"object\",\n properties: {\n query: { type: \"string\" },\n moduleId: { type: \"string\" },\n limit: { type: \"number\", default: 8 }\n },\n required: [\"query\"],\n additionalProperties: false\n },\n execute: async (_id: string, rawParams: unknown) => {\n const params = (rawParams ?? {}) as { query: string; moduleId?: string; limit?: number };\n const sitemap = await getSitemap();\n const moduleEntries = params.moduleId ? sitemap.modules.filter((item) => item.id === params.moduleId) : sitemap.modules;\n const queryTokens = tokenize(params.query);\n const intent = inferQueryIntent(params.query, queryTokens);\n const results: Array<{\n moduleId: string;\n moduleTitle: string;\n operationId: string;\n title: string;\n summary: string;\n riskLevel: string;\n reasonMatched: string[];\n score: number;\n }> = [];\n\n for (const entry of moduleEntries) {\n const moduleDoc = await getModuleDoc(entry.id);\n if (!moduleDoc) {\n continue;\n }\n for (const operation of moduleDoc.operations) {\n const score = scoreOperation(queryTokens, intent, params.moduleId, moduleDoc, operation);\n if (score < 12) {\n continue;\n }\n results.push({\n moduleId: moduleDoc.id,\n moduleTitle: moduleDoc.title,\n operationId: operation.id,\n title: operation.title,\n summary: operation.summary,\n riskLevel: operation.riskLevel,\n reasonMatched: buildMatchReasons(queryTokens, intent, moduleDoc, operation),\n score\n });\n }\n }\n\n results.sort((left, right) => right.score - left.score);\n return formatToolResult({\n query: params.query,\n moduleId: params.moduleId ?? null,\n inferredIntent: intent,\n matches: results.slice(0, Math.max(1, Math.min(params.limit ?? 8, 20)))\n });\n }\n },\n { optional: typedToolCatalog.optional ?? true }\n );\n\n api.registerTool(\n {\n name: \"redai_router_get_module\",\n description: \"Lay metadata module, feature groups, common tasks va operations shortlist.\",\n parameters: {\n type: \"object\",\n properties: {\n moduleId: { type: \"string\" },\n includeOperations: { type: \"boolean\", default: true },\n operationLimit: { type: \"number\", default: 12 }\n },\n required: [\"moduleId\"],\n additionalProperties: false\n },\n execute: async (_id: string, rawParams: unknown) => {\n const params = (rawParams ?? {}) as { moduleId: string; includeOperations?: boolean; operationLimit?: number };\n const moduleDoc = await getModuleDoc(params.moduleId);\n if (!moduleDoc) {\n return formatToolResult({ ok: false, status: 404, statusText: \"MODULE_NOT_FOUND\", data: { moduleId: params.moduleId } });\n }\n return formatToolResult({\n id: moduleDoc.id,\n title: moduleDoc.title,\n summary: moduleDoc.summary,\n purpose: moduleDoc.purpose,\n whenToUse: moduleDoc.whenToUse,\n whenNotToUse: moduleDoc.whenNotToUse,\n keywords: moduleDoc.keywords,\n commonTasks: moduleDoc.commonTasks,\n featureGroups: moduleDoc.featureGroups,\n operations:\n params.includeOperations === false\n ? undefined\n : moduleDoc.operations.slice(0, Math.max(1, Math.min(params.operationLimit ?? 12, 40))).map(summarizeOperation)\n });\n }\n },\n { optional: typedToolCatalog.optional ?? true }\n );\n\n api.registerTool(\n {\n name: \"redai_router_get_operation\",\n description: \"Lay metadata chi tiet va schema tham so cua mot operation cu the.\",\n parameters: {\n type: \"object\",\n properties: {\n operationId: { type: \"string\" }\n },\n required: [\"operationId\"],\n additionalProperties: false\n },\n execute: async (_id: string, rawParams: unknown) => {\n const params = (rawParams ?? {}) as { operationId: string };\n const operation = await findOperation(params.operationId);\n if (!operation) {\n return formatToolResult({ ok: false, status: 404, statusText: \"OPERATION_NOT_FOUND\", data: { operationId: params.operationId } });\n }\n return formatToolResult(operation);\n }\n },\n { optional: typedToolCatalog.optional ?? true }\n );\n\n api.registerTool(\n {\n name: \"redai_router_execute\",\n description: \"Execute operation thong qua router va auth RedAI da login trong DM.\",\n parameters: {\n type: \"object\",\n properties: {\n operationId: { type: \"string\" },\n telegramUserId: { type: \"string\" },\n args: { type: \"object\", additionalProperties: true },\n confirm: { type: \"boolean\", default: false }\n },\n required: [\"operationId\", \"telegramUserId\"],\n additionalProperties: false\n },\n execute: async (_id: string, rawParams: unknown) => {\n const params = (rawParams ?? {}) as {\n operationId: string;\n telegramUserId: string;\n args?: unknown;\n confirm?: boolean;\n };\n const operation = await findOperation(params.operationId);\n if (!operation) {\n return formatToolResult({ ok: false, status: 404, statusText: \"OPERATION_NOT_FOUND\", data: { operationId: params.operationId } });\n }\n if (operation.confirmationRequired && !params.confirm) {\n return formatToolResult({\n ok: false,\n status: 412,\n statusText: \"CONFIRMATION_REQUIRED\",\n data: {\n operationId: operation.id,\n title: operation.title,\n riskLevel: operation.riskLevel,\n message: \"Operation nay co risk cao hoac co tac dong that. Hay goi lai voi confirm=true sau khi da xac nhan voi user.\"\n }\n });\n }\n if (operation.riskLevel === \"destructive\" && !params.confirm) {\n return formatToolResult({\n ok: false,\n status: 412,\n statusText: \"DESTRUCTIVE_CONFIRMATION_REQUIRED\",\n data: {\n operationId: operation.id,\n title: operation.title,\n riskLevel: operation.riskLevel,\n message: \"Operation destructive bi chan mac dinh. Chi duoc goi khi user xac nhan ro va confirm=true.\"\n }\n });\n }\n\n const resolved = await resolveUserRuntimeConfig(api, params.telegramUserId);\n if (!resolved) {\n return authRequiredResult(params.telegramUserId);\n }\n\n try {\n const response = await executeOperation(resolved.scopedConfig, operation, params.args);\n return formatToolResult({\n operationId: operation.id,\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n data: response.data\n });\n } catch (error: unknown) {\n if (error instanceof RedaiAgentError) {\n return formatToolResult({\n ok: false,\n status: error.status ?? 500,\n statusText: error.message,\n data: error.body\n });\n }\n return formatToolResult({\n ok: false,\n status: 500,\n statusText: \"ROUTER_EXECUTION_FAILED\",\n data: String(error)\n });\n }\n }\n },\n { optional: typedToolCatalog.optional ?? true }\n );\n}\n","import type {\n ApiResponse,\n HeaderMap,\n HttpMethod,\n OperationRequest,\n PathParams,\n QueryParams,\n RedaiAgentClientOptions,\n TenantContext,\n ToolDescriptor,\n ToolExecutionInput\n} from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://api.redai.vn/api/v1\";\n\nconst encodeQueryValue = (value: QueryParams[string]): string[] => {\n if (value === undefined) {\n return [];\n }\n if (Array.isArray(value)) {\n return value.map((item) => String(item));\n }\n return [String(value)];\n};\n\nconst headersToObject = (headers: Headers): Record<string, string> => {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n};\n\nconst applyPathParams = (pathTemplate: string, pathParams?: PathParams): string =>\n pathTemplate.replace(/\\{([^}]+)\\}/g, (_, key: string) => {\n const raw = pathParams?.[key];\n if (raw === undefined || raw === null) {\n throw new RedaiAgentError(`Missing required path parameter: ${key}`);\n }\n return encodeURIComponent(String(raw));\n });\n\nconst buildUrl = (baseUrl: string, path: string, query?: QueryParams): URL => {\n const url = new URL(baseUrl);\n const normalizedBasePath = url.pathname.replace(/\\/+$/, \"\");\n const normalizedRequestPath = path.startsWith(\"/\") ? path : `/${path}`;\n url.pathname = `${normalizedBasePath}${normalizedRequestPath}`.replace(/\\/{2,}/g, \"/\");\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n for (const item of encodeQueryValue(value)) {\n url.searchParams.append(key, item);\n }\n }\n }\n\n return url;\n};\n\nconst parseResponse = async (response: Response): Promise<unknown> => {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return response.json();\n }\n return response.text();\n};\n\nexport class RedaiAgentError extends Error {\n status?: number;\n body?: unknown;\n\n constructor(message: string, options?: { status?: number; body?: unknown }) {\n super(message);\n this.name = \"RedaiAgentError\";\n this.status = options?.status;\n this.body = options?.body;\n }\n}\n\nexport class RedaiAgentClient {\n readonly baseUrl: string;\n\n private readonly bearerToken?: string;\n private readonly apiKey?: string;\n private readonly apiKeyHeader?: string;\n private readonly defaultHeaders?: Record<string, string>;\n private readonly timeoutMs?: number;\n private readonly fetchImpl: typeof globalThis.fetch;\n private readonly tenantContext: TenantContext;\n\n constructor(options: RedaiAgentClientOptions = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n this.bearerToken = options.bearerToken;\n this.apiKey = options.apiKey;\n this.apiKeyHeader = options.apiKeyHeader ?? \"x-api-key\";\n this.defaultHeaders = options.defaultHeaders;\n this.timeoutMs = options.timeoutMs;\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.tenantContext = {\n workspaceId: options.workspaceId,\n baseId: options.baseId\n };\n }\n\n createTenantHeaders(overrides?: TenantContext): HeaderMap {\n const workspaceId = overrides?.workspaceId ?? this.tenantContext.workspaceId;\n const baseId = overrides?.baseId ?? this.tenantContext.baseId;\n\n return {\n \"x-workspace-id\": workspaceId,\n \"x-base-id\": baseId\n };\n }\n\n async executeTool<TData = unknown>(\n tool: ToolDescriptor,\n input: ToolExecutionInput = {}\n ): Promise<ApiResponse<TData>> {\n return this.request<TData>({\n method: tool.method,\n path: tool.path,\n pathParams: input.path as PathParams | undefined,\n query: input.query,\n headers: input.headers,\n body: input.body\n });\n }\n\n async request<TData = unknown, TBody = unknown>(\n request: OperationRequest<TBody>\n ): Promise<ApiResponse<TData>> {\n const url = buildUrl(this.baseUrl, applyPathParams(request.path, request.pathParams), request.query);\n const controller = new AbortController();\n const timeout = this.timeoutMs ? setTimeout(() => controller.abort(), this.timeoutMs) : undefined;\n const headers = this.buildHeaders(request.method, request.headers, request.body !== undefined);\n\n try {\n const response = await this.fetchImpl(url, {\n method: request.method,\n headers,\n body: request.body === undefined ? undefined : JSON.stringify(request.body),\n signal: controller.signal\n });\n const data = (await parseResponse(response)) as TData;\n const result: ApiResponse<TData> = {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: headersToObject(response.headers),\n data\n };\n\n if (!response.ok) {\n throw new RedaiAgentError(`Request failed with status ${response.status}`, {\n status: response.status,\n body: data\n });\n }\n\n return result;\n } catch (error: unknown) {\n if (error instanceof RedaiAgentError) {\n throw error;\n }\n throw new RedaiAgentError(\"Request failed\", { body: error });\n } finally {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n }\n\n private buildHeaders(method: HttpMethod, requestHeaders?: HeaderMap, hasBody?: boolean): Headers {\n const headers = new Headers();\n\n for (const [key, value] of Object.entries(this.defaultHeaders ?? {})) {\n headers.set(key, value);\n }\n\n for (const [key, value] of Object.entries(this.createTenantHeaders())) {\n if (value !== undefined && value !== null && value !== \"\") {\n headers.set(key, value);\n }\n }\n\n if (this.bearerToken) {\n headers.set(\"authorization\", `Bearer ${this.bearerToken}`);\n } else if (this.apiKey) {\n headers.set(this.apiKeyHeader ?? \"x-api-key\", this.apiKey);\n }\n\n for (const [key, value] of Object.entries(requestHeaders ?? {})) {\n if (value !== undefined && value !== null && value !== \"\") {\n headers.set(key, value);\n }\n }\n\n if (!headers.has(\"accept\")) {\n headers.set(\"accept\", \"application/json\");\n }\n\n if (hasBody && method !== \"GET\" && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n return headers;\n }\n}\n","{\n \"pluginId\": \"redai-openapi-router\",\n \"pluginName\": \"RedAI OpenAPI Router\",\n \"version\": \"0.1.0\",\n \"description\": \"Router plugin de tim module, operation va execute lazy cho RedAI OpenAPI.\",\n \"optional\": true,\n \"tools\": [\n {\n \"name\": \"redai_router_list_modules\",\n \"description\": \"Liet ke cac module RedAI co san trong router.\",\n \"parameters\": { \"type\": \"object\", \"properties\": {}, \"additionalProperties\": false }\n },\n {\n \"name\": \"redai_router_search\",\n \"description\": \"Tim operation phu hop theo y nghia nghiep vu, module va tu khoa.\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"query\": { \"type\": \"string\", \"description\": \"Yeu cau nghiep vu can tim operation.\" },\n \"moduleId\": { \"type\": \"string\", \"description\": \"Loc theo module cu the neu da biet.\" },\n \"limit\": { \"type\": \"number\", \"description\": \"So ket qua toi da tra ve.\", \"default\": 8 }\n },\n \"required\": [\"query\"],\n \"additionalProperties\": false\n }\n },\n {\n \"name\": \"redai_router_get_module\",\n \"description\": \"Lay metadata module, feature groups, common tasks va operations shortlist.\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"moduleId\": { \"type\": \"string\", \"description\": \"ID module can xem.\" },\n \"includeOperations\": { \"type\": \"boolean\", \"description\": \"Co tra ve danh sach operation rut gon hay khong.\", \"default\": true },\n \"operationLimit\": { \"type\": \"number\", \"description\": \"So operation toi da tra ve khi includeOperations=true.\", \"default\": 12 }\n },\n \"required\": [\"moduleId\"],\n \"additionalProperties\": false\n }\n },\n {\n \"name\": \"redai_router_get_operation\",\n \"description\": \"Lay metadata chi tiet va schema tham so cua mot operation cu the.\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"operationId\": { \"type\": \"string\", \"description\": \"ID operation can xem.\" }\n },\n \"required\": [\"operationId\"],\n \"additionalProperties\": false\n }\n },\n {\n \"name\": \"redai_router_execute\",\n \"description\": \"Execute operation thong qua router va auth RedAI da login trong DM.\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"operationId\": { \"type\": \"string\", \"description\": \"ID operation can goi.\" },\n \"telegramUserId\": { \"type\": \"string\", \"description\": \"Telegram sender ID tu DM hien tai.\" },\n \"args\": { \"type\": \"object\", \"description\": \"Tham so operation theo shape path/query/body/headers.\", \"additionalProperties\": true },\n \"confirm\": { \"type\": \"boolean\", \"description\": \"Xac nhan cho operation co risk cao.\", \"default\": false }\n },\n \"required\": [\"operationId\", \"telegramUserId\"],\n \"additionalProperties\": false\n }\n }\n ]\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "redai-openapi-router",
|
|
3
|
+
"name": "RedAI OpenAPI Router",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Router plugin de tim module, operation va execute lazy cho 5 nhom RedAI OpenAPI trong DM.",
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"baseUrl": { "type": "string", "description": "Base URL of the target HTTP API" },
|
|
11
|
+
"bearerToken": { "type": "string", "description": "Bearer token used for Authorization header" },
|
|
12
|
+
"apiKey": { "type": "string", "description": "Static API key for the upstream API" },
|
|
13
|
+
"apiKeyHeader": { "type": "string", "description": "Header name used when apiKey is set", "default": "x-api-key" },
|
|
14
|
+
"timeoutMs": { "type": "number", "description": "Timeout in milliseconds for outbound tool calls" },
|
|
15
|
+
"defaultHeaders": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": { "type": "string" },
|
|
18
|
+
"description": "Additional headers added to every request"
|
|
19
|
+
},
|
|
20
|
+
"workspaceId": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Default workspace ID applied to x-workspace-id when the tool exposes tenant headers."
|
|
23
|
+
},
|
|
24
|
+
"baseId": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Default base ID applied to x-base-id when the tool exposes tenant headers."
|
|
27
|
+
},
|
|
28
|
+
"authStorePath": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Shared store path for per-user RedAI auth entries"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"uiHints": {
|
|
35
|
+
"baseUrl": { "label": "Base URL", "placeholder": "https://v2.redai.vn/api" },
|
|
36
|
+
"bearerToken": { "label": "Bearer Token", "sensitive": true },
|
|
37
|
+
"apiKey": { "label": "API Key", "sensitive": true },
|
|
38
|
+
"apiKeyHeader": { "label": "API Key Header" },
|
|
39
|
+
"timeoutMs": { "label": "Timeout (ms)" },
|
|
40
|
+
"workspaceId": { "label": "Workspace ID" },
|
|
41
|
+
"baseId": { "label": "Base ID" },
|
|
42
|
+
"authStorePath": { "label": "Auth Store Path" }
|
|
43
|
+
},
|
|
44
|
+
"skills": [
|
|
45
|
+
"skills/redai-openapi-router"
|
|
46
|
+
]
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@redonvn/redai-openapi-router",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Router plugin de truy van va execute catalog RedAI OpenAPI theo co che lazy.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"openclaw",
|
|
7
|
+
"plugin",
|
|
8
|
+
"router",
|
|
9
|
+
"redai",
|
|
10
|
+
"openapi"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "Redon",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"module": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"data",
|
|
28
|
+
"openclaw.plugin.json",
|
|
29
|
+
"tool-catalog.json",
|
|
30
|
+
"README.md",
|
|
31
|
+
"skills"
|
|
32
|
+
],
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@redonvn/redai-agent-sdk": "^0.1.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@redonvn/open-claw-sdk": "^0.1.5"
|
|
44
|
+
},
|
|
45
|
+
"openclaw": {
|
|
46
|
+
"extensions": [
|
|
47
|
+
"./dist/index.js"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"clean": "tsup --clean",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: redai-openapi-router
|
|
3
|
+
description: Dung khi agent can tim nhanh module RedAI, doc y nghia operation, va execute lazy thong qua router thay vi mang toan bo tool schemas vao prompt.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# RedAI OpenAPI Router
|
|
7
|
+
|
|
8
|
+
Skill nay dung cho agent khi he thong da cap plugin `redai-openapi-router`.
|
|
9
|
+
|
|
10
|
+
## Khi dung
|
|
11
|
+
|
|
12
|
+
- user hoi nghiep vu RedAI nhung chua biet dung module nao
|
|
13
|
+
- can tim operation theo y nghia nghiep vu thay vi ten tool
|
|
14
|
+
- can doc nhanh module, feature group, operation va risk truoc khi execute
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
1. Dung `redai_router_search` khi user mo ta chung chung.
|
|
19
|
+
2. Dung `redai_router_get_module` khi can hieu nhanh module va common tasks.
|
|
20
|
+
3. Dung `redai_router_get_operation` truoc khi execute operation chua ro tham so.
|
|
21
|
+
4. Neu operation co risk cao thi phai xac nhan voi user.
|
|
22
|
+
5. Chi execute bang `redai_router_execute` khi da chot dung operation va tham so.
|
|
23
|
+
|
|
24
|
+
## Quy tac
|
|
25
|
+
|
|
26
|
+
- khong doan ten tool raw khi router da co ket qua search
|
|
27
|
+
- uu tien search theo nghiep vu va context truoc, roi moi get operation schema
|
|
28
|
+
- voi operation `destructive`, `confirm_required`, `costly`, phai canh bao user truoc khi goi
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "RedAI OpenAPI Router"
|
|
3
|
+
short_description: "Route RedAI requests to the correct module and operation"
|
|
4
|
+
default_prompt: "Use $redai-openapi-router to search modules, inspect operations, and execute the correct RedAI operation lazily."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pluginId": "redai-openapi-router",
|
|
3
|
+
"pluginName": "RedAI OpenAPI Router",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Router plugin de tim module, operation va execute lazy cho RedAI OpenAPI.",
|
|
6
|
+
"optional": true,
|
|
7
|
+
"tools": [
|
|
8
|
+
{
|
|
9
|
+
"name": "redai_router_list_modules",
|
|
10
|
+
"description": "Liet ke cac module RedAI co san trong router.",
|
|
11
|
+
"parameters": { "type": "object", "properties": {}, "additionalProperties": false }
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "redai_router_search",
|
|
15
|
+
"description": "Tim operation phu hop theo y nghia nghiep vu, module va tu khoa.",
|
|
16
|
+
"parameters": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"query": { "type": "string", "description": "Yeu cau nghiep vu can tim operation." },
|
|
20
|
+
"moduleId": { "type": "string", "description": "Loc theo module cu the neu da biet." },
|
|
21
|
+
"limit": { "type": "number", "description": "So ket qua toi da tra ve.", "default": 8 }
|
|
22
|
+
},
|
|
23
|
+
"required": ["query"],
|
|
24
|
+
"additionalProperties": false
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "redai_router_get_module",
|
|
29
|
+
"description": "Lay metadata module, feature groups, common tasks va operations shortlist.",
|
|
30
|
+
"parameters": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"properties": {
|
|
33
|
+
"moduleId": { "type": "string", "description": "ID module can xem." },
|
|
34
|
+
"includeOperations": { "type": "boolean", "description": "Co tra ve danh sach operation rut gon hay khong.", "default": true },
|
|
35
|
+
"operationLimit": { "type": "number", "description": "So operation toi da tra ve khi includeOperations=true.", "default": 12 }
|
|
36
|
+
},
|
|
37
|
+
"required": ["moduleId"],
|
|
38
|
+
"additionalProperties": false
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "redai_router_get_operation",
|
|
43
|
+
"description": "Lay metadata chi tiet va schema tham so cua mot operation cu the.",
|
|
44
|
+
"parameters": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"operationId": { "type": "string", "description": "ID operation can xem." }
|
|
48
|
+
},
|
|
49
|
+
"required": ["operationId"],
|
|
50
|
+
"additionalProperties": false
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "redai_router_execute",
|
|
55
|
+
"description": "Execute operation thong qua router va auth RedAI da login trong DM.",
|
|
56
|
+
"parameters": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"properties": {
|
|
59
|
+
"operationId": { "type": "string", "description": "ID operation can goi." },
|
|
60
|
+
"telegramUserId": { "type": "string", "description": "Telegram sender ID tu DM hien tai." },
|
|
61
|
+
"args": { "type": "object", "description": "Tham so operation theo shape path/query/body/headers.", "additionalProperties": true },
|
|
62
|
+
"confirm": { "type": "boolean", "description": "Xac nhan cho operation co risk cao.", "default": false }
|
|
63
|
+
},
|
|
64
|
+
"required": ["operationId", "telegramUserId"],
|
|
65
|
+
"additionalProperties": false
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|