refactor: merge skill tool into slashcommand to reduce system prompt size
This commit is contained in:
parent
31dc6e206d
commit
8fee45401d
@ -11,7 +11,6 @@ import {
|
|||||||
createBackgroundTools,
|
createBackgroundTools,
|
||||||
createCallOmoAgent,
|
createCallOmoAgent,
|
||||||
createLookAt,
|
createLookAt,
|
||||||
createSkillTool,
|
|
||||||
createSkillMcpTool,
|
createSkillMcpTool,
|
||||||
createSlashcommandTool,
|
createSlashcommandTool,
|
||||||
createGrepTools,
|
createGrepTools,
|
||||||
@ -89,14 +88,6 @@ export function createToolRegistry(args: {
|
|||||||
|
|
||||||
const getSessionIDForMcp = (): string => getMainSessionID() || ""
|
const getSessionIDForMcp = (): string => getMainSessionID() || ""
|
||||||
|
|
||||||
const skillTool = createSkillTool({
|
|
||||||
skills: skillContext.mergedSkills,
|
|
||||||
mcpManager: managers.skillMcpManager,
|
|
||||||
getSessionID: getSessionIDForMcp,
|
|
||||||
gitMasterConfig: pluginConfig.git_master,
|
|
||||||
disabledSkills: skillContext.disabledSkills,
|
|
||||||
})
|
|
||||||
|
|
||||||
const skillMcpTool = createSkillMcpTool({
|
const skillMcpTool = createSkillMcpTool({
|
||||||
manager: managers.skillMcpManager,
|
manager: managers.skillMcpManager,
|
||||||
getLoadedSkills: () => skillContext.mergedSkills,
|
getLoadedSkills: () => skillContext.mergedSkills,
|
||||||
@ -107,6 +98,9 @@ export function createToolRegistry(args: {
|
|||||||
const slashcommandTool = createSlashcommandTool({
|
const slashcommandTool = createSlashcommandTool({
|
||||||
commands,
|
commands,
|
||||||
skills: skillContext.mergedSkills,
|
skills: skillContext.mergedSkills,
|
||||||
|
mcpManager: managers.skillMcpManager,
|
||||||
|
getSessionID: getSessionIDForMcp,
|
||||||
|
gitMasterConfig: pluginConfig.git_master,
|
||||||
})
|
})
|
||||||
|
|
||||||
const taskSystemEnabled = pluginConfig.experimental?.task_system ?? false
|
const taskSystemEnabled = pluginConfig.experimental?.task_system ?? false
|
||||||
@ -134,7 +128,6 @@ export function createToolRegistry(args: {
|
|||||||
call_omo_agent: callOmoAgent,
|
call_omo_agent: callOmoAgent,
|
||||||
...(lookAt ? { look_at: lookAt } : {}),
|
...(lookAt ? { look_at: lookAt } : {}),
|
||||||
task: delegateTask,
|
task: delegateTask,
|
||||||
skill: skillTool,
|
|
||||||
skill_mcp: skillMcpTool,
|
skill_mcp: skillMcpTool,
|
||||||
slashcommand: slashcommandTool,
|
slashcommand: slashcommandTool,
|
||||||
interactive_bash,
|
interactive_bash,
|
||||||
|
|||||||
@ -19,7 +19,6 @@ export { createSessionManagerTools } from "./session-manager"
|
|||||||
export { sessionExists } from "./session-manager/storage"
|
export { sessionExists } from "./session-manager/storage"
|
||||||
|
|
||||||
export { interactive_bash, startBackgroundCheck as startTmuxCheck } from "./interactive-bash"
|
export { interactive_bash, startBackgroundCheck as startTmuxCheck } from "./interactive-bash"
|
||||||
export { createSkillTool } from "./skill"
|
|
||||||
export { createSkillMcpTool } from "./skill-mcp"
|
export { createSkillMcpTool } from "./skill-mcp"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -137,7 +137,7 @@ export function createSkillMcpTool(options: SkillMcpToolOptions): ToolDefinition
|
|||||||
`Available MCP servers in loaded skills:\n` +
|
`Available MCP servers in loaded skills:\n` +
|
||||||
formatAvailableMcps(skills) +
|
formatAvailableMcps(skills) +
|
||||||
`\n\n` +
|
`\n\n` +
|
||||||
`Hint: Load the skill first using the 'skill' tool, then call skill_mcp.`,
|
`Hint: Load the skill first using the 'slashcommand' tool, then call skill_mcp.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
130
src/tools/slashcommand/skill-formatter.ts
Normal file
130
src/tools/slashcommand/skill-formatter.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { dirname } from "node:path"
|
||||||
|
import type { LoadedSkill } from "../../features/opencode-skill-loader"
|
||||||
|
import { extractSkillTemplate } from "../../features/opencode-skill-loader/skill-content"
|
||||||
|
import { injectGitMasterConfig as injectGitMasterConfigOriginal } from "../../features/opencode-skill-loader/skill-content"
|
||||||
|
import type { SkillMcpManager, SkillMcpClientInfo, SkillMcpServerContext } from "../../features/skill-mcp-manager"
|
||||||
|
import type { Tool, Resource, Prompt } from "@modelcontextprotocol/sdk/types.js"
|
||||||
|
|
||||||
|
export async function extractSkillBody(skill: LoadedSkill): Promise<string> {
|
||||||
|
if (skill.lazyContent) {
|
||||||
|
const fullTemplate = await skill.lazyContent.load()
|
||||||
|
const templateMatch = fullTemplate.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/)
|
||||||
|
return templateMatch ? templateMatch[1].trim() : fullTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skill.path) {
|
||||||
|
return extractSkillTemplate(skill)
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateMatch = skill.definition.template?.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/)
|
||||||
|
return templateMatch ? templateMatch[1].trim() : skill.definition.template || ""
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function formatMcpCapabilities(
|
||||||
|
skill: LoadedSkill,
|
||||||
|
manager: SkillMcpManager,
|
||||||
|
sessionID: string
|
||||||
|
): Promise<string | null> {
|
||||||
|
if (!skill.mcpConfig || Object.keys(skill.mcpConfig).length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const sections: string[] = ["", "## Available MCP Servers", ""]
|
||||||
|
|
||||||
|
for (const [serverName, config] of Object.entries(skill.mcpConfig)) {
|
||||||
|
const info: SkillMcpClientInfo = {
|
||||||
|
serverName,
|
||||||
|
skillName: skill.name,
|
||||||
|
sessionID,
|
||||||
|
}
|
||||||
|
const context: SkillMcpServerContext = {
|
||||||
|
config,
|
||||||
|
skillName: skill.name,
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.push(`### ${serverName}`)
|
||||||
|
sections.push("")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [tools, resources, prompts] = await Promise.all([
|
||||||
|
manager.listTools(info, context).catch(() => []),
|
||||||
|
manager.listResources(info, context).catch(() => []),
|
||||||
|
manager.listPrompts(info, context).catch(() => []),
|
||||||
|
])
|
||||||
|
|
||||||
|
if (tools.length > 0) {
|
||||||
|
sections.push("**Tools:**")
|
||||||
|
sections.push("")
|
||||||
|
for (const t of tools as Tool[]) {
|
||||||
|
sections.push(`#### \`${t.name}\``)
|
||||||
|
if (t.description) {
|
||||||
|
sections.push(t.description)
|
||||||
|
}
|
||||||
|
sections.push("")
|
||||||
|
sections.push("**inputSchema:**")
|
||||||
|
sections.push("```json")
|
||||||
|
sections.push(JSON.stringify(t.inputSchema, null, 2))
|
||||||
|
sections.push("```")
|
||||||
|
sections.push("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resources.length > 0) {
|
||||||
|
sections.push(`**Resources**: ${resources.map((r: Resource) => r.uri).join(", ")}`)
|
||||||
|
}
|
||||||
|
if (prompts.length > 0) {
|
||||||
|
sections.push(`**Prompts**: ${prompts.map((p: Prompt) => p.name).join(", ")}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tools.length === 0 && resources.length === 0 && prompts.length === 0) {
|
||||||
|
sections.push("*No capabilities discovered*")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||||
|
sections.push(`*Failed to connect: ${errorMessage.split("\n")[0]}*`)
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.push("")
|
||||||
|
sections.push(`Use \`skill_mcp\` tool with \`mcp_name="${serverName}"\` to invoke.`)
|
||||||
|
sections.push("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
export { injectGitMasterConfigOriginal as injectGitMasterConfig }
|
||||||
|
|
||||||
|
export async function formatSkillOutput(
|
||||||
|
skill: LoadedSkill,
|
||||||
|
mcpManager?: SkillMcpManager,
|
||||||
|
getSessionID?: () => string,
|
||||||
|
gitMasterConfig?: any
|
||||||
|
): Promise<string> {
|
||||||
|
let body = await extractSkillBody(skill)
|
||||||
|
|
||||||
|
if (skill.name === "git-master" && gitMasterConfig) {
|
||||||
|
body = injectGitMasterConfigOriginal(body, gitMasterConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dir = skill.path ? dirname(skill.path) : skill.resolvedPath || process.cwd()
|
||||||
|
|
||||||
|
const output = [
|
||||||
|
`## Skill: ${skill.name}`,
|
||||||
|
"",
|
||||||
|
`**Base directory**: ${dir}`,
|
||||||
|
"",
|
||||||
|
body,
|
||||||
|
]
|
||||||
|
|
||||||
|
if (mcpManager && getSessionID && skill.mcpConfig) {
|
||||||
|
const mcpInfo = await formatMcpCapabilities(
|
||||||
|
skill,
|
||||||
|
mcpManager,
|
||||||
|
getSessionID()
|
||||||
|
)
|
||||||
|
if (mcpInfo) {
|
||||||
|
output.push(mcpInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.join("\n")
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import { discoverCommandsSync } from "./command-discovery"
|
|||||||
import { buildDescriptionFromItems, TOOL_DESCRIPTION_PREFIX } from "./slashcommand-description"
|
import { buildDescriptionFromItems, TOOL_DESCRIPTION_PREFIX } from "./slashcommand-description"
|
||||||
import { formatCommandList, formatLoadedCommand } from "./command-output-formatter"
|
import { formatCommandList, formatLoadedCommand } from "./command-output-formatter"
|
||||||
import { skillToCommandInfo } from "./skill-command-converter"
|
import { skillToCommandInfo } from "./skill-command-converter"
|
||||||
|
import { formatSkillOutput } from "./skill-formatter"
|
||||||
|
|
||||||
export function createSlashcommandTool(options: SlashcommandToolOptions = {}): ToolDefinition {
|
export function createSlashcommandTool(options: SlashcommandToolOptions = {}): ToolDefinition {
|
||||||
let cachedCommands: CommandInfo[] | null = options.commands ?? null
|
let cachedCommands: CommandInfo[] | null = options.commands ?? null
|
||||||
@ -75,6 +76,18 @@ export function createSlashcommandTool(options: SlashcommandToolOptions = {}): T
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (exactMatch) {
|
if (exactMatch) {
|
||||||
|
const skills = await getSkills()
|
||||||
|
const matchedSkill = skills.find(s => s.name === exactMatch.name)
|
||||||
|
|
||||||
|
if (matchedSkill) {
|
||||||
|
return await formatSkillOutput(
|
||||||
|
matchedSkill,
|
||||||
|
options.mcpManager,
|
||||||
|
options.getSessionID,
|
||||||
|
options.gitMasterConfig
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return await formatLoadedCommand(exactMatch, args.user_message)
|
return await formatLoadedCommand(exactMatch, args.user_message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import type { LoadedSkill, LazyContentLoader } from "../../features/opencode-skill-loader"
|
import type { LoadedSkill, LazyContentLoader } from "../../features/opencode-skill-loader"
|
||||||
|
import type { SkillMcpManager } from "../../features/skill-mcp-manager"
|
||||||
|
import type { GitMasterConfig } from "../../config/schema/git-master"
|
||||||
|
|
||||||
export type CommandScope = "builtin" | "config" | "user" | "project" | "opencode" | "opencode-project"
|
export type CommandScope = "builtin" | "config" | "user" | "project" | "opencode" | "opencode-project"
|
||||||
|
|
||||||
@ -25,4 +27,10 @@ export interface SlashcommandToolOptions {
|
|||||||
commands?: CommandInfo[]
|
commands?: CommandInfo[]
|
||||||
/** Pre-loaded skills (skip discovery if provided) */
|
/** Pre-loaded skills (skip discovery if provided) */
|
||||||
skills?: LoadedSkill[]
|
skills?: LoadedSkill[]
|
||||||
|
/** MCP manager for skill MCP capabilities */
|
||||||
|
mcpManager?: SkillMcpManager
|
||||||
|
/** Function to get current session ID */
|
||||||
|
getSessionID?: () => string
|
||||||
|
/** Git master configuration */
|
||||||
|
gitMasterConfig?: GitMasterConfig
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user