Skip to main content
Glama

GenAIScript

Official
by microsoft
MIT License
43
2,820
  • Linux
  • Apple
chatparticipant.ts9.16 kB
// cspell: disable import * as vscode from "vscode" import { ExtensionState } from "./state" import { COPILOT_CHAT_PARTICIPANT_SCRIPT_ID, COPILOT_CHAT_PARTICIPANT_ID, ICON_LOGO_NAME, MODEL_PROVIDER_GITHUB_COPILOT_CHAT, } from "../../core/src/constants" import { Fragment } from "../../core/src/generation" import { convertAnnotationsToItems } from "../../core/src/annotations" import { deleteUndefinedValues } from "../../core/src/cleaners" import { patchCachedImages } from "../../core/src/filecache" export async function activateChatParticipant(state: ExtensionState) { const { context } = state const { subscriptions } = context const resolveReference = ( references: readonly vscode.ChatPromptReference[] ): { files: string[]; vars: Record<string, string> } => { const files = [] const vars: Record<string, string> = {} for (const reference of references) { const { id, value } = reference if (typeof value === "string") vars[id] = value else if (value instanceof vscode.Uri) files.push(vscode.workspace.asRelativePath(value, false)) else if (value instanceof vscode.Location) files.push(vscode.workspace.asRelativePath(value.uri, false)) // TODO range else state.output.appendLine( `unknown reference type: ${typeof value}` ) } return { files, vars } } const participant = vscode.chat.createChatParticipant( COPILOT_CHAT_PARTICIPANT_ID, async ( request: vscode.ChatRequest, context: vscode.ChatContext, response: vscode.ChatResponseStream, token: vscode.CancellationToken ) => { let { command, prompt, references, model } = request const md = (t: string, ...enabledCommands: string[]) => { const ms = new vscode.MarkdownString(t + "\n", true) if (enabledCommands.length) ms.isTrusted = { enabledCommands, } response.markdown(ms) } // this command does not require any parsing if (command === "models") { const chatModels = await vscode.lm.selectChatModels() const languageChatModels = await state.languageChatModels() md(`This is the current model alias mapping:\n`) for (const chatModel of chatModels) { md( `- \`${languageChatModels[chatModel.id] || "---"}\` > \`${chatModel.id}\`, ${chatModel.name}, max ${chatModel.maxInputTokens}\n` ) } return } // parse and analyze results await state.parseWorkspace() if (token.isCancellationRequested) return const { project } = state const templates = project.scripts .filter((s) => !s.isSystem && !s.unlisted) .sort((a, b) => a.id.localeCompare(b.id)) const mdHelp = () => md( `\n\n[Docs](https://microsoft.github.io/genaiscript/reference/vscode/github-copilot-chat/) | [Samples](https://microsoft.github.io/genaiscript/samples/)\n` ) const mdEmpty = () => md( `\n😞 Oops, I could not find any genaiscript. [Create a new script](command:genaiscript.prompt.create)?\n`, "genaiscript.prompt.create" ) const mdTemplateList = () => { templates.forEach((s) => { response.markdown(`- \`${s.id}\`: `) if (s.filename) response.anchor(vscode.Uri.file(s.filename), s.id) response.markdown(` ${s.title}\n`) }) } // list command if (command === "list") { if (templates.length) { md("Use `@genaiscript /run <scriptid> ...` with:\n") mdTemplateList() } else { mdEmpty() } mdHelp() return } // try resolving template or handling run let scriptid = "" let template: PromptScript if (command === "run") { scriptid = prompt.split(" ")[0] prompt = prompt.slice(scriptid.length).trim() template = templates.find((t) => t.id === scriptid) } else { template = templates.find( (t) => t.id === COPILOT_CHAT_PARTICIPANT_SCRIPT_ID ) } // tell user which templates are available if (!template) { if (scriptid === "") md(`😓 Please specify a genaiscript to run.\n`) else md( `😕 Oops, I could not find any genaiscript matching \`${scriptid}\`.\n` ) if (templates.length === 0) { mdEmpty() } else { md(`Try one of the following:\n`) mdTemplateList() } mdHelp() return } const { files, vars } = resolveReference(references) const history = renderHistory(context) const fragment: Fragment = { files, } const canceller = token.onCancellationRequested( async () => await state.cancelAiRequest() ) const res = await state.requestAI({ scriptId: template.id, label: "genaiscript agent", parameters: deleteUndefinedValues({ ...vars, "copilot.history": history, "copilot.model": `${MODEL_PROVIDER_GITHUB_COPILOT_CHAT}:${model.id}`, question: prompt, }), githubCopilotChatModelId: model.id, fragment, mode: "chat", }) canceller.dispose() if (token.isCancellationRequested) return const { text = "", status, statusText, runId } = res || {} if (status !== "success") md("$(error) " + statusText) if (text) { let patched = convertAnnotationsToItems(text) const dir = state.host.projectUri patched = patchCachedImages(patched, (url) => { const wurl = vscode.Uri.joinPath(dir, url).toString() state.output.appendLine(`image: ${url}`) state.output.appendLine(` ${wurl}`) return wurl }) md("\n\n" + patched) } // TODO open url if (runId) { const server = state.host.server md( `\n\n[Trace](${server.browserUrl}#scriptid=${template.id}&runid=${res.runId})` ) } } ) participant.iconPath = new vscode.ThemeIcon(ICON_LOGO_NAME) subscriptions.push(participant) } function renderHistory( context: vscode.ChatContext ): (HistoryMessageUser | HistoryMessageAssistant)[] { const { history } = context if (!history?.length) return undefined const res = history .map((message) => { if (message instanceof vscode.ChatRequestTurn) { return { role: "user", content: message.prompt, } satisfies HistoryMessageUser } else if (message instanceof vscode.ChatResponseTurn) { return { role: "assistant", name: message.participant, content: message.response .map((r) => { if (r instanceof vscode.ChatResponseMarkdownPart) { return r.value.value } else if ( r instanceof vscode.ChatResponseAnchorPart ) { if (r.value instanceof vscode.Uri) return vscode.workspace.asRelativePath( r.value.fsPath ) else return vscode.workspace.asRelativePath( r.value.uri.fsPath ) } return "" }) .join(""), } as HistoryMessageAssistant } else return undefined }) .filter((f) => !!f) return res.length ? res : undefined }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/microsoft/genaiscript'

If you have feedback or need assistance with the MCP directory API, please join our Discord server