Skip to content

Commit

Permalink
chore: update pnpm lockfile for modelcontextprotocoltools dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
arafatkatze committed Jan 15, 2025
1 parent 1c16f35 commit b408de1
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 26 deletions.
1 change: 1 addition & 0 deletions lib/shared/src/context/openctx/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export const REMOTE_DIRECTORY_PROVIDER_URI = 'internal-remote-directory-search'
export const WEB_PROVIDER_URI = 'internal-web-provider'
export const GIT_OPENCTX_PROVIDER_URI = 'internal-git-openctx-provider'
export const CODE_SEARCH_PROVIDER_URI = 'internal-code-search-provider'
export const MODEL_CONTEXT_PROVIDER_URI = 'internal-model-context-provider'
1 change: 1 addition & 0 deletions lib/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ export {
WEB_PROVIDER_URI,
GIT_OPENCTX_PROVIDER_URI,
CODE_SEARCH_PROVIDER_URI,
MODEL_CONTEXT_PROVIDER_URI,
} from './context/openctx/api'
export * from './context/openctx/context'
export * from './lexicalEditor/editorState'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"update-agent-recordings": "pnpm build && CODY_KEEP_UNUSED_RECORDINGS=false CODY_RECORD_IF_MISSING=true vitest agent/src",
"update-agent-recordings-windows": "PowerShell -ExecutionPolicy Bypass -Command \"pnpm build; if ($?) { $Env:CODY_KEEP_UNUSED_RECORDINGS='false'; $Env:CODY_RECORD_IF_MISSING='true'; vitest agent/src }\"",
"update-rewrite-recordings": "rm -rf recordings && CODY_RECORD_IF_MISSING=true CODY_RECORDING_MODE=record vitest vscode/src/local-context/rewrite-keyword-query.test.ts",
"openctx:link": "cd ../openctx && pnpm -C lib/client link --global && pnpm -C lib/schema link --global && pnpm -C lib/protocol link --global && pnpm -C client/vscode-lib link --global && cd ../cody && pnpm link --global @openctx/client && pnpm link --global @openctx/schema && pnpm link --global @openctx/protocol && cd vscode && pnpm link --global @openctx/vscode-lib",
"openctx:link": "cd ../openctx && pnpm -C lib/client link --global && pnpm -C lib/schema link --global && pnpm -C lib/protocol link --global && pnpm -C client/vscode-lib link --global && pnpm -C provider/modelcontextprotocoltools link --global && cd ../cody && pnpm link --global @openctx/client && pnpm link --global @openctx/schema && pnpm link --global @openctx/protocol && pnpm link --global @openctx/provider-modelcontextprotocoltools && cd vscode && pnpm link --global @openctx/vscode-lib",
"openctx:unlink": "pnpm unlink --global @openctx/client && pnpm unlink --global @openctx/schema && pnpm unlink --global @openctx/protocol && cd vscode && pnpm unlink --global @openctx/vscode-lib",
"vsce-version-bump": "pnpm -C vscode version-bump:minor"
},
Expand Down
10 changes: 10 additions & 0 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,16 @@
"markdownDescription": "OpenCtx providers configuration.",
"default": {}
},
"openctx.mcp.enable": {
"type": "boolean",
"markdownDescription": "Enable OpenCtx providers for Cody.",
"default": true
},
"openctx.mcp.uri": {
"type": "string",
"markdownDescription": "URI for the MCP provider tools in OpenCtx.",
"default": ""
},
"cody.internal.unstable": {
"order": 999,
"type": "boolean",
Expand Down
102 changes: 100 additions & 2 deletions vscode/src/chat/agentic/CodyTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
ContextItemSource,
type ContextItemWithContent,
type ContextMentionProviderMetadata,
MODEL_CONTEXT_PROVIDER_URI,
type MentionQuery,
PromptString,
firstValueFrom,
logDebug,
Expand All @@ -15,6 +17,7 @@ import {
import { URI } from 'vscode-uri'
import { getContextFromRelativePath } from '../../commands/context/file-path'
import { getContextFileFromShell } from '../../commands/context/shell'
import type { OpenCtxProvider } from '../../context/openctx/types'
import { type ContextRetriever, toStructuredMentions } from '../chat-view/ContextRetriever'
import { getChatContextItemsForMention } from '../context/chatContext'
import { getCorpusContextItemsForEditorState } from '../initialContext'
Expand Down Expand Up @@ -94,7 +97,7 @@ export abstract class CodyTool {
/**
* Resets the raw text input stream.
*/
private reset(): void {
public reset(): void {
this.unprocessedText = ''
}
/**
Expand Down Expand Up @@ -148,7 +151,7 @@ class CliTool extends CodyTool {
},
prompt: {
instruction: ps`Reject all unsafe and harmful commands with <ban> tags. Execute safe command for its output with <cmd> tags`,
placeholder: ps`SAFE_COMMAND`,
placeholder: PromptString.unsafe_fromUserQuery('INPUT'),
examples: [
ps`Get output for git diff: \`<TOOLCLI><cmd>git diff</cmd></TOOLCLI>\``,
ps`List files in a directory: \`<TOOLCLI><cmd>ls -l</cmd></TOOLCLI>\``,
Expand Down Expand Up @@ -257,6 +260,56 @@ class SearchTool extends CodyTool {
}
}

export class ModelContextProviderTool extends CodyTool {
constructor(
config: CodyToolConfig,
private modelContextProvider: OpenCtxProvider,
private toolName: string
) {
super(config)
}

public parse(): string[] {
try {
JSON.parse(this.unprocessedText)
} catch {
return []
}
const unparsedText = this.unprocessedText
this.reset()
return [unparsedText]
}

public async execute(span: Span, queries: string[]): Promise<ContextItem[]> {
span.addEvent('executeModelContextProviderTool')

try {
const rawItems =
(await this.modelContextProvider.items?.(
{ mention: { title: this.toolName, data: JSON.parse('{}'), uri: '' } },
{}
)) ?? []

return rawItems.map(item => ({
type: 'openctx',
provider: 'openctx',
title: item.title,
uri: URI.parse(''),
providerUri: MODEL_CONTEXT_PROVIDER_URI,
content: item.ai?.content || '',
mention: {
uri: '',
data: item.ai,
description: item.ai?.content,
},
}))
} catch (error) {
console.error('ModelContextProviderTool execution failed:', error)
return []
}
}
}

/**
* Tool for interacting with OpenCtx providers and retrieving context items.
*/
Expand All @@ -268,6 +321,23 @@ export class OpenCtxTool extends CodyTool {
super(config)
}

parse(): string[] {
if (this.provider.id === 'internal-model-context-provider') {
return [this.unprocessedText]
}
return super.parse()
}

parseMCPMentionQuery(
query: string,
idObject: Pick<ContextMentionProviderMetadata, 'id'>
): MentionQuery {
return {
provider: idObject.id,
text: query,
}
}

async execute(span: Span, queries: string[]): Promise<ContextItem[]> {
span.addEvent('executeOpenCtxTool')
const openCtxClient = openCtx.controller
Expand All @@ -279,7 +349,35 @@ export class OpenCtxTool extends CodyTool {
try {
// TODO: Investigate if we can batch queries for better performance.
// For example, would it cause issues if we fire 10 requests to a OpenCtx provider for fetching Linear?
const toolName = this.config.title

console.log('toolName', toolName)

for (const query of queries) {
if (this.provider.id === 'internal-model-context-provider') {
const mcpResults = await openCtxClient.items(
{ mention: { uri: '', title: this.config.title, data: JSON.parse(query) } },
{ providerUri: MODEL_CONTEXT_PROVIDER_URI }
)
console.log(mcpResults)
const itemsWithContent = mcpResults.map(item => ({
type: 'openctx' as const,
title: item.title || '',
uri: URI.parse(''),
providerUri: MODEL_CONTEXT_PROVIDER_URI,
content: item.ai?.content || '',
provider: 'openctx' as const,
source: ContextItemSource.Agentic,
mention: {
uri: '',
data: item.ai,
description: item.ai?.content,
},
}))
results.push(...itemsWithContent)
continue
}

const mention = parseMentionQuery(query, idObject)
// First get the items without content
const openCtxItems = await getChatContextItemsForMention({ mentionQuery: mention })
Expand Down
131 changes: 109 additions & 22 deletions vscode/src/chat/agentic/CodyToolProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,63 @@ class ToolFactory {
.filter(isDefined)
}

public createOpenCtxTools(providers: ContextMentionProviderMetadata[]): CodyTool[] {
return providers
.map(provider => {
public async createOpenCtxTools(providers: ContextMentionProviderMetadata[]): Promise<CodyTool[]> {
const tools: CodyTool[] = []

for (const provider of providers) {
if (provider.id === 'internal-model-context-provider') {
// For MCP providers, get available tools through the mentions() function
// get the Vscode Regex Here for query
const mcpTools =
(await openCtx.controller?.mentions(
{ query: 'echo' },
{ providerUri: provider.id }
)) ?? []

for (const mcpTool of mcpTools) {
const toolName = this.generateToolName({
...provider,
title: mcpTool.title ?? provider.title,
})
const config = this.createModelContextConfig(
{
title: mcpTool.title ?? '',
description: mcpTool.description ?? '',
data: mcpTool.data,
},
toolName
)

this.register({
name: toolName,
...config,
createInstance: cfg => new OpenCtxTool(provider, cfg),
})

const tool = this.createTool(toolName)
if (tool) {
tools.push(tool)
}
}
} else {
// For regular providers, create a single tool as before
const toolName = this.generateToolName(provider)
const config = this.getToolConfig(provider)

this.register({
name: toolName,
...config,
createInstance: cfg => new OpenCtxTool(provider, cfg),
})
return this.createTool(toolName)
})
.filter(isDefined)

const tool = this.createTool(toolName)
if (tool) {
tools.push(tool)
}
}
}

return tools
}

private generateToolName(provider: ContextMentionProviderMetadata): string {
Expand All @@ -124,20 +168,57 @@ class ToolFactory {
const defaultConfig = Object.entries(OPENCTX_TOOL_CONFIG).find(
c => provider.id.toLowerCase().includes(c[0]) || provider.title.toLowerCase().includes(c[0])
)
return (
defaultConfig?.[1] ?? {
title: provider.title,
tags: {
tag: PromptString.unsafe_fromUserQuery(this.generateToolName(provider)),
subTag: ps`get`,
},
prompt: {
instruction: PromptString.unsafe_fromUserQuery(provider.queryLabel),
placeholder: ps`QUERY`,
examples: [],
},
}
)
if (defaultConfig) {
return defaultConfig[1]
}
return {
title: provider.title,
tags: {
tag: PromptString.unsafe_fromUserQuery(this.generateToolName(provider)),
subTag: ps`get`,
},
prompt: {
instruction: PromptString.unsafe_fromUserQuery(provider.queryLabel),
placeholder: ps`QUERY`,
examples: [],
},
}
}
// TODO: Handles this in getToolConfig instead of
// having a separate function specific to model context protocol
private createModelContextConfig(
mention: {
title: string
description: string
data?: any
},
tagName: string
): CodyToolConfig {
// Extract schema properties for better instruction formatting
const schemaProperties = mention.data?.properties || {}

return {
title: mention.title,
tags: {
tag: PromptString.unsafe_fromUserQuery(tagName),
subTag: ps`QUERY`,
},
prompt: {
instruction: PromptString.unsafe_fromUserQuery(
`Use ${mention.title} to ${mention.description || 'retrieve context'}. ` +
`Input must follow this schema::\n${JSON.stringify(schemaProperties, null, 2)}` +
'Ensure all required properties are provided and types match the schema.'
),
placeholder: PromptString.unsafe_fromUserQuery('INPUT'),
examples: [
PromptString.unsafe_fromUserQuery(
`To use ${mention.title} with valid schema: \`<${tagName}>${JSON.stringify({
message: mention.data?.properties || 'example input',
})}</${tagName}>\``
),
],
},
}
}
}

Expand Down Expand Up @@ -185,8 +266,14 @@ export class CodyToolProvider {
if (provider && !CodyToolProvider.openCtxSubscription && openCtx.controller) {
CodyToolProvider.openCtxSubscription = openCtx.controller
.metaChanges({}, {})
.pipe(map(providers => providers.filter(p => !!p.mentions).map(openCtxProviderMetadata)))
.subscribe(providerMeta => provider.factory.createOpenCtxTools(providerMeta))
.pipe(
map(providers =>
providers.filter(p => !!p.mentions).map(p => openCtxProviderMetadata(p))
)
)
.subscribe(async providers => {
provider.factory.createOpenCtxTools(providers)
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion vscode/src/chat/context/chatContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export async function getChatContextItemsForMention(
if (!openCtx.controller) {
return []
}

// For MCP provider, we need to call items() with the mention
const items = await openCtx.controller.mentions(
{
query: mentionQuery.text,
Expand Down
10 changes: 10 additions & 0 deletions vscode/src/context/openctx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type ClientConfiguration,
FeatureFlag,
GIT_OPENCTX_PROVIDER_URI,
MODEL_CONTEXT_PROVIDER_URI,
WEB_PROVIDER_URI,
authStatus,
clientCapabilities,
Expand Down Expand Up @@ -35,6 +36,7 @@ import { logDebug } from '../output-channel-logger'
import { createCodeSearchProvider } from './openctx/codeSearch'
import { gitMentionsProvider } from './openctx/git'
import LinearIssuesProvider from './openctx/linear-issues'
import { createModelContextProvider } from './openctx/modelContextProvider'
import RemoteDirectoryProvider, { createRemoteDirectoryProvider } from './openctx/remoteDirectorySearch'
import RemoteFileProvider, { createRemoteFileProvider } from './openctx/remoteFileSearch'
import RemoteRepositorySearch, { createRemoteRepositoryProvider } from './openctx/remoteRepositorySearch'
Expand Down Expand Up @@ -185,6 +187,14 @@ export function getOpenCtxProviders(
providerUri: CODE_SEARCH_PROVIDER_URI,
})
}
// enable MCP provider
providers.push({
settings: true,
provider: createModelContextProvider(
'file:///Users/arafatkhan/Desktop/servers/src/everything/dist/index.js'
),
providerUri: MODEL_CONTEXT_PROVIDER_URI,
})

return providers
}
Expand Down
Loading

0 comments on commit b408de1

Please sign in to comment.