feat(core): register mcp prompt commands
This commit is contained in:
parent
7d4965cb29
commit
1c5dda1bc6
7 changed files with 81 additions and 0 deletions
|
|
@ -2564,6 +2564,7 @@ export type CommandsListOutput = {
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly agent?: string
|
readonly agent?: string
|
||||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string }
|
||||||
|
readonly source?: "command" | "mcp" | "skill"
|
||||||
readonly subtask?: boolean
|
readonly subtask?: boolean
|
||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ export const Plugin = define({
|
||||||
for (const [name, command] of Object.entries(document.commands ?? {})) {
|
for (const [name, command] of Object.entries(document.commands ?? {})) {
|
||||||
draft.update(name, (item) => {
|
draft.update(name, (item) => {
|
||||||
item.template = command.template
|
item.template = command.template
|
||||||
|
item.source = "command"
|
||||||
if (command.description !== undefined) item.description = command.description
|
if (command.description !== undefined) item.description = command.description
|
||||||
if (command.agent !== undefined) item.agent = command.agent
|
if (command.agent !== undefined) item.agent = command.agent
|
||||||
if (command.model !== undefined) {
|
if (command.model !== undefined) {
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@ export const Plugin = define({
|
||||||
draft.update("init", (command) => {
|
draft.update("init", (command) => {
|
||||||
command.template = PROMPT_INITIALIZE.replace("${path}", location.project.directory)
|
command.template = PROMPT_INITIALIZE.replace("${path}", location.project.directory)
|
||||||
command.description = "guided AGENTS.md setup"
|
command.description = "guided AGENTS.md setup"
|
||||||
|
command.source = "command"
|
||||||
})
|
})
|
||||||
draft.update("review", (command) => {
|
draft.update("review", (command) => {
|
||||||
command.template = PROMPT_REVIEW.replace("${path}", location.project.directory)
|
command.template = PROMPT_REVIEW.replace("${path}", location.project.directory)
|
||||||
command.description = "review changes [commit|branch|pr], defaults to uncommitted"
|
command.description = "review changes [commit|branch|pr], defaults to uncommitted"
|
||||||
|
command.source = "command"
|
||||||
command.subtask = true
|
command.subtask = true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import { Global } from "../global"
|
||||||
import { Integration } from "../integration"
|
import { Integration } from "../integration"
|
||||||
import { Location } from "../location"
|
import { Location } from "../location"
|
||||||
import { ModelsDev } from "../models-dev"
|
import { ModelsDev } from "../models-dev"
|
||||||
|
import { MCP } from "../mcp"
|
||||||
import { Npm } from "../npm"
|
import { Npm } from "../npm"
|
||||||
import { PluginV2 } from "../plugin"
|
import { PluginV2 } from "../plugin"
|
||||||
import { Reference } from "../reference"
|
import { Reference } from "../reference"
|
||||||
|
|
@ -30,6 +31,7 @@ import { FetchHttpClient, HttpClient } from "effect/unstable/http"
|
||||||
import { AgentPlugin } from "./agent"
|
import { AgentPlugin } from "./agent"
|
||||||
import { CommandPlugin } from "./command"
|
import { CommandPlugin } from "./command"
|
||||||
import { ModelsDevPlugin } from "./models-dev"
|
import { ModelsDevPlugin } from "./models-dev"
|
||||||
|
import { MCPCommandPlugin } from "./mcp-command"
|
||||||
import { ProviderPlugins } from "./provider"
|
import { ProviderPlugins } from "./provider"
|
||||||
import { SdkPlugins } from "./sdk"
|
import { SdkPlugins } from "./sdk"
|
||||||
import { SkillPlugin } from "./skill"
|
import { SkillPlugin } from "./skill"
|
||||||
|
|
@ -48,6 +50,7 @@ export type Requirements =
|
||||||
| Integration.Service
|
| Integration.Service
|
||||||
| Location.Service
|
| Location.Service
|
||||||
| ModelsDev.Service
|
| ModelsDev.Service
|
||||||
|
| MCP.Service
|
||||||
| Npm.Service
|
| Npm.Service
|
||||||
| Reference.Service
|
| Reference.Service
|
||||||
| SkillV2.Service
|
| SkillV2.Service
|
||||||
|
|
@ -72,6 +75,7 @@ const layer = Layer.effectDiscard(
|
||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
const modelsDev = yield* ModelsDev.Service
|
const modelsDev = yield* ModelsDev.Service
|
||||||
|
const mcp = yield* MCP.Service
|
||||||
const npm = yield* Npm.Service
|
const npm = yield* Npm.Service
|
||||||
const events = yield* EventV2.Service
|
const events = yield* EventV2.Service
|
||||||
const fs = yield* FSUtil.Service
|
const fs = yield* FSUtil.Service
|
||||||
|
|
@ -94,6 +98,7 @@ const layer = Layer.effectDiscard(
|
||||||
Effect.provideService(Config.Service, config),
|
Effect.provideService(Config.Service, config),
|
||||||
Effect.provideService(Location.Service, location),
|
Effect.provideService(Location.Service, location),
|
||||||
Effect.provideService(ModelsDev.Service, modelsDev),
|
Effect.provideService(ModelsDev.Service, modelsDev),
|
||||||
|
Effect.provideService(MCP.Service, mcp),
|
||||||
Effect.provideService(Npm.Service, npm),
|
Effect.provideService(Npm.Service, npm),
|
||||||
Effect.provideService(EventV2.Service, events),
|
Effect.provideService(EventV2.Service, events),
|
||||||
Effect.provideService(FSUtil.Service, fs),
|
Effect.provideService(FSUtil.Service, fs),
|
||||||
|
|
@ -116,6 +121,7 @@ const layer = Layer.effectDiscard(
|
||||||
yield* add(ModelsDevPlugin)
|
yield* add(ModelsDevPlugin)
|
||||||
yield* add(ConfigAgentPlugin.Plugin)
|
yield* add(ConfigAgentPlugin.Plugin)
|
||||||
yield* add(ConfigCommandPlugin.Plugin)
|
yield* add(ConfigCommandPlugin.Plugin)
|
||||||
|
yield* add(MCPCommandPlugin.Plugin)
|
||||||
yield* add(ConfigSkillPlugin.Plugin)
|
yield* add(ConfigSkillPlugin.Plugin)
|
||||||
for (const item of ProviderPlugins) yield* add(item)
|
for (const item of ProviderPlugins) yield* add(item)
|
||||||
yield* add(ConfigExternalPlugin.Plugin)
|
yield* add(ConfigExternalPlugin.Plugin)
|
||||||
|
|
@ -147,6 +153,7 @@ export const node = makeLocationNode({
|
||||||
Config.node,
|
Config.node,
|
||||||
Location.node,
|
Location.node,
|
||||||
ModelsDev.node,
|
ModelsDev.node,
|
||||||
|
MCP.node,
|
||||||
Npm.node,
|
Npm.node,
|
||||||
EventV2.node,
|
EventV2.node,
|
||||||
FSUtil.node,
|
FSUtil.node,
|
||||||
|
|
|
||||||
68
packages/core/src/plugin/mcp-command.ts
Normal file
68
packages/core/src/plugin/mcp-command.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
export * as MCPCommandPlugin from "./mcp-command"
|
||||||
|
|
||||||
|
import { Effect } from "effect"
|
||||||
|
import { MCP } from "../mcp"
|
||||||
|
import { define } from "./internal"
|
||||||
|
|
||||||
|
export const Plugin = define({
|
||||||
|
id: "mcp-command",
|
||||||
|
effect: Effect.fn(function* (ctx) {
|
||||||
|
const mcp = yield* MCP.Service
|
||||||
|
yield* Effect.gen(function* () {
|
||||||
|
const prompts = yield* mcp.prompts()
|
||||||
|
const commands = yield* Effect.forEach(
|
||||||
|
prompts,
|
||||||
|
(prompt) =>
|
||||||
|
mcp
|
||||||
|
.prompt({
|
||||||
|
server: prompt.server,
|
||||||
|
name: prompt.name,
|
||||||
|
args: Object.fromEntries(prompt.arguments?.map((argument, index) => [argument.name, `$${index + 1}`]) ?? []),
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
Effect.map((result) => ({
|
||||||
|
name: `${sanitize(prompt.server)}:${sanitize(prompt.name)}`,
|
||||||
|
description: prompt.description,
|
||||||
|
template: promptText(result),
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
{ concurrency: "unbounded" },
|
||||||
|
)
|
||||||
|
yield* ctx.command.transform((draft) => {
|
||||||
|
for (const command of commands) {
|
||||||
|
const template = command.template
|
||||||
|
if (!template || draft.get(command.name)) continue
|
||||||
|
draft.update(command.name, (item) => {
|
||||||
|
item.template = template
|
||||||
|
item.source = "mcp"
|
||||||
|
if (command.description !== undefined) item.description = command.description
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).pipe(
|
||||||
|
Effect.tapError((error) =>
|
||||||
|
Effect.logWarning("failed to register MCP prompt commands", {
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Effect.ignore,
|
||||||
|
Effect.forkScoped,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
function promptText(result: MCP.PromptResult | undefined) {
|
||||||
|
const text = result?.messages
|
||||||
|
.flatMap((message) => {
|
||||||
|
const content = message.content
|
||||||
|
if (!content || typeof content !== "object") return []
|
||||||
|
if (!("type" in content) || content.type !== "text") return []
|
||||||
|
if (!("text" in content) || typeof content.text !== "string") return []
|
||||||
|
return [content.text]
|
||||||
|
})
|
||||||
|
.join("\n")
|
||||||
|
.trim()
|
||||||
|
return text || undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitize = (value: string) => value.replace(/[^a-zA-Z0-9_-]/g, "_")
|
||||||
|
|
@ -11,5 +11,6 @@ export const Info = Schema.Struct({
|
||||||
description: Schema.String.pipe(optional),
|
description: Schema.String.pipe(optional),
|
||||||
agent: Schema.String.pipe(optional),
|
agent: Schema.String.pipe(optional),
|
||||||
model: Model.Ref.pipe(optional),
|
model: Model.Ref.pipe(optional),
|
||||||
|
source: Schema.Literals(["command", "mcp", "skill"]).pipe(optional),
|
||||||
subtask: Schema.Boolean.pipe(optional),
|
subtask: Schema.Boolean.pipe(optional),
|
||||||
}).annotate({ identifier: "CommandV2.Info" })
|
}).annotate({ identifier: "CommandV2.Info" })
|
||||||
|
|
|
||||||
|
|
@ -5145,6 +5145,7 @@ export type CommandV2Info = {
|
||||||
description?: string
|
description?: string
|
||||||
agent?: string
|
agent?: string
|
||||||
model?: ModelRef
|
model?: ModelRef
|
||||||
|
source?: "command" | "mcp" | "skill"
|
||||||
subtask?: boolean
|
subtask?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue