From 2bc6daa081b61988f8114bbe5bc6d0aea2f4ed05 Mon Sep 17 00:00:00 2001 From: Naman Kumar Date: Tue, 3 Sep 2024 11:05:32 +0530 Subject: [PATCH] Include initial context from OpenCtx providers. (#5433) context: https://linear.app/sourcegraph/issue/PROD-264/one-pager-for-how-to-get-this-set-up-using-openctx We have [added](https://github.com/sourcegraph/openctx/pull/199) `meta.mentions.autoInclude` property for OpenCtx providers. The providers which set that to `true` will be used to include the mentions they return as initial context items. We are also passing the active file uri and codebase names to the `mentions` function. ## Test plan Set the following as the vs code setting and see the hello world mention item chip appearing as the default context item. ```json "openctx.providers": { "https://openctx.org/npm/@openctx/provider-hello-world": true } ``` ## Changelog Include initial context from OpenCtx providers. --- package.json | 2 +- pnpm-lock.yaml | 107 +++++++++--------- vscode/package.json | 4 +- vscode/src/chat/clientStateBroadcaster.ts | 33 +++++- vscode/src/chat/context/chatContext.ts | 21 +++- .../repository/repo-metadata-from-git-api.ts | 6 +- web/package.json | 2 +- 7 files changed, 114 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index c09cf630e968..9ec42dfdeb67 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "vitest": "^2.0.5" }, "dependencies": { - "@openctx/client": "^0.0.25", + "@openctx/client": "^0.0.26", "@sourcegraph/telemetry": "^0.18.0", "ignore": "^5.3.1", "observable-fns": "^0.6.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79587cda901f..c2fbfba31044 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: .: dependencies: '@openctx/client': - specifier: ^0.0.25 - version: 0.0.25 + specifier: ^0.0.26 + version: 0.0.26 '@sourcegraph/telemetry': specifier: ^0.18.0 version: 0.18.0 @@ -421,11 +421,11 @@ importers: specifier: ^0.20.8 version: 0.20.8 '@openctx/provider-linear-issues': - specifier: ^0.0.6 - version: 0.0.6 + specifier: ^0.0.7 + version: 0.0.7 '@openctx/vscode-lib': - specifier: ^0.0.21 - version: 0.0.21 + specifier: ^0.0.22 + version: 0.0.22 '@opentelemetry/api': specifier: ^1.7.0 version: 1.7.0 @@ -821,8 +821,8 @@ importers: web: devDependencies: '@openctx/vscode-lib': - specifier: ^0.0.21 - version: 0.0.21 + specifier: ^0.0.22 + version: 0.0.22 '@sourcegraph/cody': specifier: workspace:* version: link:../agent @@ -3357,12 +3357,12 @@ packages: which: 4.0.0 dev: true - /@openctx/client@0.0.25: - resolution: {integrity: sha512-jvwuLBfJrokzF1o/b155rLN18+YOQS3xttw+f1ZpKlC470u1aUHS+pasEcQ9Ty5ygBRoUVkKjRKkRTXgZ45foQ==} + /@openctx/client@0.0.26: + resolution: {integrity: sha512-PapkkZVGZBbYjOnMeqFhy5H4VzAtD0+3vAyLClXn2w6N5rhoJeGdNhQyyBuDnB5doJDY8RWV7paWbCCRZ2FYNg==} dependencies: - '@openctx/protocol': 0.0.16 - '@openctx/provider': 0.0.15 - '@openctx/schema': 0.0.12 + '@openctx/protocol': 0.0.17 + '@openctx/provider': 0.0.16 + '@openctx/schema': 0.0.13 lru-cache: 10.2.2 observable-fns: 0.6.1 picomatch: 3.0.1 @@ -3373,13 +3373,13 @@ packages: '@openctx/schema': 0.0.12 dev: false - /@openctx/protocol@0.0.16: - resolution: {integrity: sha512-W8kRJPpbYVCK0vfel4NByq7wfpTwa1+1TpsA79X12Eta+PstPqCbMUEGjwTeruilzVpIdros26rm4nCsx7MctA==} + /@openctx/protocol@0.0.17: + resolution: {integrity: sha512-wTRDeubjgcNEaKu2hretjl57QSpafAEWO9TxjYfdnxBRSxOmWz/QHgm+vqTZKNyAAc38f3apL0G3jGQJGQ2fQQ==} dependencies: - '@openctx/schema': 0.0.12 + '@openctx/schema': 0.0.13 - /@openctx/provider-linear-issues@0.0.6: - resolution: {integrity: sha512-h1N8OtATRDIVB/VJ/m3WBFdVQBwFpa1RHlDiNhg8znCAK9qhw6Y/GMTl89Q6IBZwIdFQ2uxxzF7d8bkyBIiEDQ==} + /@openctx/provider-linear-issues@0.0.7: + resolution: {integrity: sha512-8NzRAoojj4o1c7+KaMTIc/e/cdVgiRbY4j2U5rn9K0qF2InZ6XNajdbvFdPT+PGrOzNOSvPiVFSM5OX/jKesSg==} dependencies: '@openctx/provider': 0.0.14 dedent: 1.5.3 @@ -3396,29 +3396,33 @@ packages: picomatch: 3.0.1 dev: false - /@openctx/provider@0.0.15: - resolution: {integrity: sha512-7jEBI7EcExFOKk1OE91YJhYxLlqzFGWDuu01YHd6CBmq0Eo5IxezEosUn7FvKnTyA0ywoRpT27PI9OX0Lqu/Ag==} + /@openctx/provider@0.0.16: + resolution: {integrity: sha512-5fK/UXPyBbeW1xE8nBOhu3xJhNNT2E+8mLsHb7tCdcRArgapk9+MsJaFiUGUZMbZ+f839c8YaZhN0CXo84No1Q==} dependencies: - '@openctx/protocol': 0.0.16 - '@openctx/schema': 0.0.12 + '@openctx/protocol': 0.0.17 + '@openctx/schema': 0.0.13 picomatch: 3.0.1 /@openctx/schema@0.0.12: resolution: {integrity: sha512-YEqmuasaOeAtcrhlN3/D6r+76J/omRbSBUPbv4azKQA7CDvG9MnfgV1Gv8JbFSz33XzI1h9wGbPi5uzb6o6peQ==} + dev: false - /@openctx/ui-common@0.0.11: - resolution: {integrity: sha512-3HESG+9UyAra9grHkyI9Fh6d6U5GAcz/kQ3cgOJgICR9Rx0WoTHrr3wgs7V0gOY3fJaL5f6wXEATBbRK3wOwqg==} + /@openctx/schema@0.0.13: + resolution: {integrity: sha512-P7pi+zkmq+gQkFWZTOjREnQQGmWtMRtHWSFEUt+G3B4Du1D8qFYxOWE4gH4gqlgNISeFS1UrbvGfSAds4jx0yA==} + + /@openctx/ui-common@0.0.12: + resolution: {integrity: sha512-FhKswG4GEVWI3YxIIweNywQr+7yjLxjKj0+OiYHvyjg108XKVSWb1TyqPiMjpYVJNFnKLHGKQqe7V9K3vDbCyQ==} dependencies: - '@openctx/schema': 0.0.12 + '@openctx/schema': 0.0.13 marked: 12.0.2 sanitize-html: 2.13.0 xss: 1.0.15 - /@openctx/vscode-lib@0.0.21: - resolution: {integrity: sha512-WFV3GQz8aB0bri4YRKTNcav2OFLlqNDEb9H1fIFqxZ8lg12S53xjye/VdyMg96y0be5TSImpPwGekG0qP8oFOQ==} + /@openctx/vscode-lib@0.0.22: + resolution: {integrity: sha512-FrjY39+qIr4fW69HThN3VNgfUsZDPCBvI5NZhwuI6TExKc5rWsDT/rFNyR5vlkesS/xRJ0B6wlFuYGK5JSY6Xg==} dependencies: - '@openctx/client': 0.0.25 - '@openctx/ui-common': 0.0.11 + '@openctx/client': 0.0.26 + '@openctx/ui-common': 0.0.12 observable-fns: 0.6.1 /@opentelemetry/api-logs@0.45.1: @@ -6911,7 +6915,7 @@ packages: esbuild: '>=0.10.0' dependencies: esbuild: 0.18.20 - tslib: 2.6.3 + tslib: 2.7.0 dev: true /@yarnpkg/fslib@2.10.3: @@ -7147,7 +7151,7 @@ packages: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} dependencies: - tslib: 2.6.3 + tslib: 2.1.0 dev: false /aria-query@5.1.3: @@ -7231,7 +7235,7 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} dependencies: - tslib: 2.6.3 + tslib: 2.1.0 dev: true /astral-regex@2.0.0: @@ -7242,7 +7246,7 @@ packages: /async-mutex@0.4.0: resolution: {integrity: sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==} dependencies: - tslib: 2.6.3 + tslib: 2.7.0 dev: false /async@3.2.5: @@ -8729,7 +8733,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.1.0 dev: true /dotenv-expand@10.0.0: @@ -11374,7 +11378,7 @@ packages: /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: - tslib: 2.6.3 + tslib: 2.1.0 dev: true /lowlight@2.9.0: @@ -12417,7 +12421,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.6.3 + tslib: 2.1.0 dev: true /nocache@3.0.4: @@ -13620,7 +13624,7 @@ packages: '@types/react': 18.2.37 react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.37)(react@18.2.0) - tslib: 2.6.3 + tslib: 2.1.0 dev: false /react-remove-scroll-bar@2.3.6(@types/react@18.2.79)(react@18.2.0): @@ -13636,7 +13640,7 @@ packages: '@types/react': 18.2.79 react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.2.0) - tslib: 2.6.3 + tslib: 2.1.0 dev: false /react-remove-scroll@2.5.5(@types/react@18.2.37)(react@18.2.0): @@ -13653,7 +13657,7 @@ packages: react: 18.2.0 react-remove-scroll-bar: 2.3.6(@types/react@18.2.37)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.37)(react@18.2.0) - tslib: 2.6.3 + tslib: 2.1.0 use-callback-ref: 1.3.2(@types/react@18.2.37)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.37)(react@18.2.0) dev: false @@ -13672,7 +13676,7 @@ packages: react: 18.2.0 react-remove-scroll-bar: 2.3.6(@types/react@18.2.79)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.2.0) - tslib: 2.6.3 + tslib: 2.1.0 use-callback-ref: 1.3.2(@types/react@18.2.79)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.79)(react@18.2.0) dev: false @@ -13691,7 +13695,7 @@ packages: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 - tslib: 2.6.3 + tslib: 2.1.0 dev: false /react-style-singleton@2.2.1(@types/react@18.2.79)(react@18.2.0): @@ -13708,7 +13712,7 @@ packages: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 - tslib: 2.6.3 + tslib: 2.1.0 dev: false /react@18.2.0: @@ -13818,7 +13822,7 @@ packages: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.6.3 + tslib: 2.1.0 dev: true /redent@3.0.0: @@ -14159,7 +14163,7 @@ packages: /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: - tslib: 2.6.3 + tslib: 2.1.0 dev: true /safe-buffer@5.1.2: @@ -14408,7 +14412,7 @@ packages: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.1.0 dev: true /snapdragon-node@2.1.1: @@ -15335,10 +15339,9 @@ packages: /tslib@2.1.0: resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==} - dev: false - /tslib@2.6.3: - resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + /tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} /tsscmp@1.0.6: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} @@ -15735,7 +15738,7 @@ packages: dependencies: '@types/react': 18.2.37 react: 18.2.0 - tslib: 2.6.3 + tslib: 2.1.0 dev: false /use-callback-ref@1.3.2(@types/react@18.2.79)(react@18.2.0): @@ -15750,7 +15753,7 @@ packages: dependencies: '@types/react': 18.2.79 react: 18.2.0 - tslib: 2.6.3 + tslib: 2.1.0 dev: false /use-sidecar@1.1.2(@types/react@18.2.37)(react@18.2.0): @@ -15766,7 +15769,7 @@ packages: '@types/react': 18.2.37 detect-node-es: 1.1.0 react: 18.2.0 - tslib: 2.6.3 + tslib: 2.1.0 dev: false /use-sidecar@1.1.2(@types/react@18.2.79)(react@18.2.0): @@ -15782,7 +15785,7 @@ packages: '@types/react': 18.2.79 detect-node-es: 1.1.0 react: 18.2.0 - tslib: 2.6.3 + tslib: 2.1.0 dev: false /use@3.1.1: diff --git a/vscode/package.json b/vscode/package.json index ccce347def76..7abad8d25fea 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -1354,8 +1354,8 @@ }, "dependencies": { "@anthropic-ai/sdk": "^0.20.8", - "@openctx/provider-linear-issues": "^0.0.6", - "@openctx/vscode-lib": "^0.0.21", + "@openctx/provider-linear-issues": "^0.0.7", + "@openctx/vscode-lib": "^0.0.22", "@opentelemetry/api": "^1.7.0", "@opentelemetry/core": "^1.18.1", "@opentelemetry/exporter-trace-otlp-http": "^0.45.1", diff --git a/vscode/src/chat/clientStateBroadcaster.ts b/vscode/src/chat/clientStateBroadcaster.ts index 56525af80638..ba094cdf50aa 100644 --- a/vscode/src/chat/clientStateBroadcaster.ts +++ b/vscode/src/chat/clientStateBroadcaster.ts @@ -1,5 +1,6 @@ import { type ContextItem, + type ContextItemOpenCtx, ContextItemSource, type ContextItemTree, REMOTE_REPOSITORY_PROVIDER_URI, @@ -7,15 +8,20 @@ import { displayLineRange, displayPathBasename, expandToLineRange, + openCtx, subscriptionDisposable, } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' +import { URI } from 'vscode-uri' import { getSelectionOrFileContext } from '../commands/context/selection' import { createRepositoryMention } from '../context/openctx/common/get-repository-mentions' import { workspaceReposMonitor } from '../repository/repo-metadata-from-git-api' import { authProvider } from '../services/AuthProvider' import type { ChatModel } from './chat-view/ChatModel' -import { contextItemMentionFromOpenCtxItem } from './context/chatContext' +import { + contextItemMentionFromOpenCtxItem, + getActiveEditorContextForOpenCtxMentions, +} from './context/chatContext' import type { ExtensionMessage } from './protocol' type PostMessage = (message: Extract) => void @@ -153,7 +159,30 @@ export async function getCorpusContextItemsForEditorState(useRemote: boolean): P } } - return items + const providers = (await openCtx.controller?.meta({}))?.filter(meta => meta.mentions?.autoInclude) + if (!providers) { + return items + } + + const activeEditorContext = await getActiveEditorContextForOpenCtxMentions() + + const openctxMentions = ( + await Promise.all( + providers.map(async (provider): Promise => { + const mentions = + (await openCtx?.controller?.mentions(activeEditorContext, provider)) || [] + + return mentions.map(mention => ({ + ...mention, + provider: 'openctx', + type: 'openctx', + uri: URI.parse(mention.uri), + })) + }) + ) + ).flat() + + return [...items, ...openctxMentions] } function idempotentPostMessage(rawPostMessage: PostMessage): PostMessage { diff --git a/vscode/src/chat/context/chatContext.ts b/vscode/src/chat/context/chatContext.ts index 20860b5b528a..c297d84d693f 100644 --- a/vscode/src/chat/context/chatContext.ts +++ b/vscode/src/chat/context/chatContext.ts @@ -27,6 +27,10 @@ import { getOpenTabsContextFile, getSymbolContextFiles, } from '../../editor/utils/editor-context' +import { + fetchRepoMetadataForFolder, + workspaceReposMonitor, +} from '../../repository/repo-metadata-from-git-api' import type { ChatModel } from '../chat-view/ChatModel' interface GetContextItemsTelemetry { @@ -162,7 +166,7 @@ export async function getChatContextItemsForMention( } const items = await openCtx.controller.mentions( - { query: mentionQuery.text }, + { query: mentionQuery.text, ...(await getActiveEditorContextForOpenCtxMentions()) }, // get mention items for the selected provider only. { providerUri: mentionQuery.provider } ) @@ -174,6 +178,21 @@ export async function getChatContextItemsForMention( } } +export async function getActiveEditorContextForOpenCtxMentions(): Promise<{ + uri: string | undefined + codebase: string | undefined +}> { + const uri = vscode.window.activeTextEditor?.document.uri?.toString() + const activeWorkspaceURI = + uri && + workspaceReposMonitor?.getFolderURIs().find(folderURI => uri?.startsWith(folderURI.toString())) + + const codebase = + activeWorkspaceURI && (await fetchRepoMetadataForFolder(activeWorkspaceURI))[0]?.repoName + + return { uri, codebase } +} + export function contextItemMentionFromOpenCtxItem( item: Mention & { providerUri: string } ): ContextItemOpenCtx | ContextItemRepository { diff --git a/vscode/src/repository/repo-metadata-from-git-api.ts b/vscode/src/repository/repo-metadata-from-git-api.ts index 9744ecceb91d..e822a3c853db 100644 --- a/vscode/src/repository/repo-metadata-from-git-api.ts +++ b/vscode/src/repository/repo-metadata-from-git-api.ts @@ -64,7 +64,7 @@ class WorkspaceReposMonitor implements vscode.Disposable { return repoMetadata.flat() } - private getFolderURIs(): vscode.Uri[] { + public getFolderURIs(): vscode.Uri[] { return vscode.workspace.workspaceFolders?.map(f => f.uri) ?? [] } @@ -128,7 +128,9 @@ export function initWorkspaceReposMonitor( return workspaceReposMonitor } -async function fetchRepoMetadataForFolder(folderURI: vscode.Uri): Promise { +export async function fetchRepoMetadataForFolder( + folderURI: vscode.Uri +): Promise { const repoNames = await repoNameResolver.getRepoNamesFromWorkspaceUri(folderURI) if (repoNames.length === 0) { return [] diff --git a/web/package.json b/web/package.json index 1fbfdc301a5b..8309dd38316c 100644 --- a/web/package.json +++ b/web/package.json @@ -19,7 +19,7 @@ "build-ts": "tsc --build" }, "devDependencies": { - "@openctx/vscode-lib": "^0.0.21", + "@openctx/vscode-lib": "^0.0.22", "@sourcegraph/cody": "workspace:*", "@sourcegraph/cody-shared": "workspace:*", "@sourcegraph/prompt-editor": "workspace:*",