mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 17:47:27 +00:00
♻️ refactor: change the klavis github tools into lobehub skill & add vercel skills (#13442)
* refactor: change the klavis github tools into lobehub skill & add the vercel skill * fix: slove the test & topicid parse
This commit is contained in:
parent
fee0fe5699
commit
19f90e3d9a
13 changed files with 57 additions and 26 deletions
|
|
@ -266,7 +266,7 @@
|
|||
"@lobehub/desktop-ipc-typings": "workspace:*",
|
||||
"@lobehub/editor": "^4.5.0",
|
||||
"@lobehub/icons": "^5.0.0",
|
||||
"@lobehub/market-sdk": "0.31.11",
|
||||
"@lobehub/market-sdk": "0.32.2",
|
||||
"@lobehub/tts": "^5.1.2",
|
||||
"@lobehub/ui": "^5.6.1",
|
||||
"@modelcontextprotocol/sdk": "^1.26.0",
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ export class CredsExecutionRuntime {
|
|||
const providerConfig = getLobehubSkillProviderById(provider);
|
||||
if (!providerConfig) {
|
||||
return {
|
||||
content: `Unknown OAuth provider: ${provider}. Available providers: github, linear, microsoft, twitter`,
|
||||
content: `Unknown OAuth provider: ${provider}. Available providers: github, linear, microsoft, twitter, vercel`,
|
||||
error: {
|
||||
message: `Unknown OAuth provider: ${provider}`,
|
||||
type: 'UnknownProvider',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { IconType } from '@icons-pack/react-simple-icons';
|
||||
import { SiCaldotcom, SiGithub } from '@icons-pack/react-simple-icons';
|
||||
import { SiCaldotcom } from '@icons-pack/react-simple-icons';
|
||||
import { Klavis } from 'klavis';
|
||||
|
||||
export interface KlavisServerType {
|
||||
|
|
@ -96,17 +96,6 @@ export const KLAVIS_SERVER_TYPES: KlavisServerType[] = [
|
|||
label: 'Google Docs',
|
||||
serverName: Klavis.McpServerName.GoogleDocs,
|
||||
},
|
||||
{
|
||||
author: 'Klavis',
|
||||
authorUrl: 'https://klavis.io',
|
||||
description: 'Enhanced GitHub MCP Server',
|
||||
icon: SiGithub,
|
||||
identifier: 'github',
|
||||
readme:
|
||||
'Connect to GitHub to manage repositories, issues, pull requests, and code. Search code, review changes, create branches, and collaborate on software development projects through conversational AI.',
|
||||
label: 'GitHub',
|
||||
serverName: Klavis.McpServerName.Github,
|
||||
},
|
||||
{
|
||||
author: 'Klavis',
|
||||
authorUrl: 'https://klavis.io',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { IconType } from '@icons-pack/react-simple-icons';
|
||||
import { SiGithub, SiLinear, SiX } from '@icons-pack/react-simple-icons';
|
||||
import { SiGithub, SiLinear, SiVercel, SiX } from '@icons-pack/react-simple-icons';
|
||||
|
||||
export interface LobehubSkillProviderType {
|
||||
/**
|
||||
|
|
@ -93,6 +93,18 @@ export const LOBEHUB_SKILL_PROVIDERS: LobehubSkillProviderType[] = [
|
|||
'Connect to X (Twitter) to post tweets, manage your timeline, and engage with your audience. Create content, schedule posts, monitor mentions, and build your social media presence through conversational AI.',
|
||||
label: 'X (Twitter)',
|
||||
},
|
||||
{
|
||||
author: 'LobeHub',
|
||||
authorUrl: 'https://lobehub.com',
|
||||
defaultVisible: true,
|
||||
description:
|
||||
'Vercel is a cloud platform for frontend developers, providing hosting and serverless functions to deploy web applications with ease.',
|
||||
icon: SiVercel,
|
||||
id: 'vercel',
|
||||
readme:
|
||||
'Connect to Vercel to manage your deployments, monitor project status, and control your infrastructure. Deploy applications, check build logs, manage environment variables, and scale your projects through conversational AI.',
|
||||
label: 'Vercel',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"@lobechat/python-interpreter": "workspace:*",
|
||||
"@lobechat/web-crawler": "workspace:*",
|
||||
"@lobehub/chat-plugin-sdk": "^1.32.4",
|
||||
"@lobehub/market-sdk": "0.31.11",
|
||||
"@lobehub/market-sdk": "0.32.2",
|
||||
"@lobehub/market-types": "^1.12.3",
|
||||
"model-bank": "workspace:*",
|
||||
"type-fest": "^4.41.0",
|
||||
|
|
|
|||
|
|
@ -398,16 +398,18 @@ export const marketRouter = router({
|
|||
args: z.record(z.any()).optional(),
|
||||
provider: z.string(),
|
||||
toolName: z.string(),
|
||||
topicId: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { provider, toolName, args } = input;
|
||||
log('connectCallTool: provider=%s, tool=%s', provider, toolName);
|
||||
|
||||
const { provider, toolName, args, topicId } = input;
|
||||
log('connectCallTool: provider=%s, tool=%s, topicId=%s', provider, toolName, topicId);
|
||||
try {
|
||||
const response = await ctx.marketSDK.skills.callTool(provider, {
|
||||
args: args || {},
|
||||
tool: toolName,
|
||||
// @ts-ignore
|
||||
topicId,
|
||||
});
|
||||
|
||||
log('connectCallTool response: %O', response);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ export function extractAccessToken(req: NextRequest): string | undefined {
|
|||
|
||||
export interface LobehubSkillExecuteParams {
|
||||
args: Record<string, any>;
|
||||
context?: {
|
||||
topicId?: string;
|
||||
};
|
||||
provider: string;
|
||||
toolName: string;
|
||||
}
|
||||
|
|
@ -460,13 +463,15 @@ export class MarketService {
|
|||
* @returns Execution result with content and success status
|
||||
*/
|
||||
async executeLobehubSkill(params: LobehubSkillExecuteParams): Promise<LobehubSkillExecuteResult> {
|
||||
const { provider, toolName, args } = params;
|
||||
const { provider, toolName, args, context } = params;
|
||||
|
||||
log('executeLobehubSkill: %s/%s with args: %O', provider, toolName, args);
|
||||
log('executeLobehubSkill: %s/%s with args: %O, context: %O', provider, toolName, args, context);
|
||||
|
||||
try {
|
||||
const response = await this.market.skills.callTool(provider, {
|
||||
args,
|
||||
// @ts-ignore
|
||||
topicId: context?.topicId,
|
||||
tool: toolName,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ export class BuiltinToolsExecutor implements IToolExecutor {
|
|||
if (source === 'lobehubSkill') {
|
||||
return this.marketService.executeLobehubSkill({
|
||||
args,
|
||||
context: {
|
||||
topicId: context.topicId,
|
||||
},
|
||||
provider: identifier,
|
||||
toolName: apiName,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,12 +4,24 @@ import { useToolStore } from '@/store/tool';
|
|||
import { type ChatToolPayload } from '@/types/message';
|
||||
import { safeParseJSON } from '@/utils/safeParseJSON';
|
||||
|
||||
/**
|
||||
* Context for remote tool execution, derived from the invoking message
|
||||
*/
|
||||
export interface RemoteToolExecutorContext {
|
||||
/** Topic ID from the message that triggered this tool call */
|
||||
topicId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executor function type for remote tool invocation
|
||||
* @param payload - Tool call payload
|
||||
* @param context - Context from the invoking message
|
||||
* @returns Promise with MCPToolCallResult data
|
||||
*/
|
||||
export type RemoteToolExecutor = (payload: ChatToolPayload) => Promise<MCPToolCallResult>;
|
||||
export type RemoteToolExecutor = (
|
||||
payload: ChatToolPayload,
|
||||
context?: RemoteToolExecutorContext,
|
||||
) => Promise<MCPToolCallResult>;
|
||||
|
||||
/**
|
||||
* Create a failed MCPToolCallResult
|
||||
|
|
@ -23,7 +35,7 @@ const createFailedResult = (
|
|||
success: false,
|
||||
});
|
||||
|
||||
export const klavisExecutor: RemoteToolExecutor = async (p) => {
|
||||
export const klavisExecutor: RemoteToolExecutor = async (p, _context) => {
|
||||
// payload.identifier is now the storage identifier (e.g., 'google-calendar')
|
||||
const identifier = p.identifier;
|
||||
const klavisServers = useToolStore.getState().servers || [];
|
||||
|
|
@ -62,7 +74,7 @@ export const klavisExecutor: RemoteToolExecutor = async (p) => {
|
|||
return createFailedResult('Klavis tool returned empty result');
|
||||
};
|
||||
|
||||
export const lobehubSkillExecutor: RemoteToolExecutor = async (p: any) => {
|
||||
export const lobehubSkillExecutor: RemoteToolExecutor = async (p, context) => {
|
||||
// payload.identifier is the provider id (e.g., 'linear', 'microsoft')
|
||||
const provider = p.identifier;
|
||||
|
||||
|
|
@ -70,10 +82,12 @@ export const lobehubSkillExecutor: RemoteToolExecutor = async (p: any) => {
|
|||
const args = safeParseJSON(p.arguments) || {};
|
||||
|
||||
// Call LobeHub Skill tool via store action
|
||||
// topicId comes from message context, not global active state
|
||||
const result = await useToolStore.getState().callLobehubSkillTool({
|
||||
args,
|
||||
provider,
|
||||
toolName: p.apiName,
|
||||
topicId: context?.topicId,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
|
|
|
|||
|
|
@ -357,7 +357,9 @@ export class PluginTypesActionImpl {
|
|||
);
|
||||
|
||||
try {
|
||||
data = await executor(payload);
|
||||
// Pass topicId from message context, not global active state
|
||||
// This ensures tool calls use the correct topic even if user switches topics
|
||||
data = await executor(payload, { topicId: message?.topicId });
|
||||
} catch (error) {
|
||||
console.error(`[${logPrefix}] Error:`, error);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ describe('lobehubSkillStore actions', () => {
|
|||
provider: 'linear',
|
||||
toolName: 'createIssue',
|
||||
args: { title: 'Test Issue' },
|
||||
topicId: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export class LobehubSkillStoreActionImpl {
|
|||
callLobehubSkillTool = async (
|
||||
params: CallLobehubSkillToolParams,
|
||||
): Promise<CallLobehubSkillToolResult> => {
|
||||
const { provider, toolName, args } = params;
|
||||
const { provider, toolName, args, topicId } = params;
|
||||
const toolId = `${provider}:${toolName}`;
|
||||
|
||||
this.#set(
|
||||
|
|
@ -56,6 +56,7 @@ export class LobehubSkillStoreActionImpl {
|
|||
args,
|
||||
provider,
|
||||
toolName,
|
||||
topicId,
|
||||
});
|
||||
|
||||
this.#set(
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ export interface CallLobehubSkillToolParams {
|
|||
provider: string;
|
||||
/** Tool name */
|
||||
toolName: string;
|
||||
/** Topic ID from message context (not global active state) */
|
||||
topicId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue