Skip to content

Commit

Permalink
Cody standalone web app prototype and dev helper (#4047)
Browse files Browse the repository at this point in the history
  • Loading branch information
sqs committed May 18, 2024
1 parent 3e0eb2d commit 695d262
Show file tree
Hide file tree
Showing 38 changed files with 945 additions and 202 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules/
.stylelintcache
dist/
out/
*.tsbuildinfo
.DS_Store
.env
Expand Down
30 changes: 22 additions & 8 deletions agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import type { TelemetryEventParameters } from '@sourcegraph/telemetry'
import { chatHistory } from '../../vscode/src/chat/chat-view/ChatHistoryManager'
import { SimpleChatModel } from '../../vscode/src/chat/chat-view/SimpleChatModel'
import type { ExtensionMessage, WebviewMessage } from '../../vscode/src/chat/protocol'
import { activate } from '../../vscode/src/extension.node'
import { ProtocolTextDocumentWithUri } from '../../vscode/src/jsonrpc/TextDocumentWithUri'

import type { Har } from '@pollyjs/persister'
Expand Down Expand Up @@ -79,8 +78,15 @@ import * as vscode_shim from './vscode-shim'
const inMemorySecretStorageMap = new Map<string, string>()
const globalState = new AgentGlobalState()

/** The VS Code extension's `activate` function. */
type ExtensionActivate = (
context: vscode.ExtensionContext,
extensionClient?: ExtensionClient
) => Promise<unknown>

export async function initializeVscodeExtension(
workspaceRoot: vscode.Uri,
extensionActivate: ExtensionActivate,
extensionClient: ExtensionClient
): Promise<void> {
const paths = envPaths('Cody')
Expand Down Expand Up @@ -121,7 +127,7 @@ export async function initializeVscodeExtension(
globalStoragePath: vscode.Uri.file(paths.data).fsPath,
}

await activate(context, extensionClient)
await extensionActivate(context, extensionClient)
}

export async function newAgentClient(
Expand Down Expand Up @@ -164,7 +170,10 @@ export async function newAgentClient(
})
}

export async function newEmbeddedAgentClient(clientInfo: ClientInfo): Promise<Agent> {
export async function newEmbeddedAgentClient(
clientInfo: ClientInfo,
extensionActivate: ExtensionActivate
): Promise<Agent> {
process.env.ENABLE_SENTRY = 'false'

// Create noop MessageConnection because we're just using clientForThisInstance.
Expand All @@ -180,7 +189,7 @@ export async function newEmbeddedAgentClient(clientInfo: ClientInfo): Promise<Ag
})()
)

const agent = new Agent({ conn })
const agent = new Agent({ conn, extensionActivate })
agent.registerNotification('debug/message', params => {
console.error(`${params.channel}: ${params.message}`)
})
Expand Down Expand Up @@ -276,6 +285,7 @@ export class Agent extends MessageHandler implements ExtensionClient {
networkRequests?: Request[]
requestErrors?: PollyRequestError[]
conn: MessageConnection
extensionActivate: ExtensionActivate
}
) {
super(params.conn)
Expand Down Expand Up @@ -330,7 +340,11 @@ export class Agent extends MessageHandler implements ExtensionClient {
path: clientInfo.workspaceRootPath,
})
try {
await initializeVscodeExtension(this.workspace.workspaceRootUri, this)
await initializeVscodeExtension(
this.workspace.workspaceRootUri,
params.extensionActivate,
this
)
this.registerWebviewHandlers()

this.authenticationPromise = clientInfo.extensionConfiguration
Expand Down Expand Up @@ -444,13 +458,13 @@ export class Agent extends MessageHandler implements ExtensionClient {
})

this.registerAuthenticatedRequest('testing/networkRequests', async () => {
const requests = this.params?.networkRequests ?? []
const requests = this.params.networkRequests ?? []
return {
requests: requests.map(req => ({ url: req.url, body: req.body })),
}
})
this.registerAuthenticatedRequest('testing/closestPostData', async ({ url, postData }) => {
const polly = this.params?.polly
const polly = this.params.polly
let closestDistance = Number.MAX_VALUE
let closest = ''
if (polly) {
Expand All @@ -473,7 +487,7 @@ export class Agent extends MessageHandler implements ExtensionClient {
return { closestBody: closest }
})
this.registerAuthenticatedRequest('testing/requestErrors', async () => {
const requests = this.params?.requestErrors ?? []
const requests = this.params.requestErrors ?? []
return {
errors: requests.map(({ request, error }) => ({
url: request.url,
Expand Down
32 changes: 20 additions & 12 deletions agent/src/bfg/BfgRetriever.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BfgRetriever } from '../../../vscode/src/completions/context/retrievers
import { getCurrentDocContext } from '../../../vscode/src/completions/get-current-doc-context'
import { initTreeSitterParser } from '../../../vscode/src/completions/test-helpers'
import { defaultVSCodeExtensionClient } from '../../../vscode/src/extension-client'
import { activate } from '../../../vscode/src/extension.node'
import { initializeVscodeExtension, newEmbeddedAgentClient } from '../agent'
import * as vscode_shim from '../vscode-shim'

Expand All @@ -35,7 +36,11 @@ describe('BfgRetriever', async () => {
beforeAll(async () => {
process.env.CODY_TESTING = 'true'
await initTreeSitterParser()
await initializeVscodeExtension(vscode.Uri.file(process.cwd()), defaultVSCodeExtensionClient())
await initializeVscodeExtension(
vscode.Uri.file(process.cwd()),
activate,
defaultVSCodeExtensionClient()
)

if (shouldCreateGitDir) {
await exec('git init', { cwd: dir })
Expand All @@ -58,19 +63,22 @@ describe('BfgRetriever', async () => {
// To fix this test the following functionality should be implemented:
// - https://github.com/sourcegraph/cody/issues/4137
// - https://github.com/sourcegraph/cody/issues/4138
const agent = await newEmbeddedAgentClient({
name: 'BfgContextFetcher',
version: '0.1.0',
workspaceRootUri: rootUri.toString(),
extensionConfiguration: {
accessToken: '',
serverEndpoint: '',
customHeaders: {},
customConfiguration: {
'cody.experimental.cody-engine.await-indexing': true,
const agent = await newEmbeddedAgentClient(
{
name: 'BfgContextFetcher',
version: '0.1.0',
workspaceRootUri: rootUri.toString(),
extensionConfiguration: {
accessToken: '',
serverEndpoint: '',
customHeaders: {},
customConfiguration: {
'cody.experimental.cody-engine.await-indexing': true,
},
},
},
})
activate
)
const client = agent.clientForThisInstance()

const filePath = path.join(dir, testFile)
Expand Down
3 changes: 2 additions & 1 deletion agent/src/cli/jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { StreamMessageReader, StreamMessageWriter, createMessageConnection } fro
import { startPollyRecording } from '../../../vscode/src/testutils/polly'
import { Agent } from '../agent'

import { activate } from '../../../vscode/src/extension.node'
import { booleanOption } from './evaluate-autocomplete/cli-parsers'

interface JsonrpcCommandOptions {
Expand Down Expand Up @@ -186,7 +187,7 @@ function setupAgentCommunication(params: {
new StreamMessageWriter(params.stdout)
)

new Agent({ ...params, conn })
new Agent({ ...params, conn, extensionActivate: activate })

// Force the agent process to exit when stdin/stdout close as an attempt to
// prevent zombie agent processes. We experienced this problem when we
Expand Down
2 changes: 1 addition & 1 deletion agent/src/vscode-shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ export const commands = _commands as typeof vscode.commands

const _env: Partial<typeof vscode.env> = {
uriScheme: 'file',
appRoot: process.cwd(),
appRoot: process.cwd?.(),
uiKind: UIKind.Web,
language: process.env.language,
clipboard: {
Expand Down
26 changes: 22 additions & 4 deletions lib/shared/src/sourcegraph-api/completions/browserClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class SourcegraphBrowserCompletionsClient extends SourcegraphCompletionsC
if (this.config.accessToken) {
headersInstance.set('Authorization', `token ${this.config.accessToken}`)
}
const parameters = new URLSearchParams(window.location.search)
const parameters = new URLSearchParams(globalThis.location.search)
const trace = parameters.get('trace')
if (trace) {
headersInstance.set('X-Sourcegraph-Should-Trace', 'true')
Expand Down Expand Up @@ -95,6 +95,7 @@ export class SourcegraphBrowserCompletionsClient extends SourcegraphCompletionsC
// throw the error for not retrying
throw error
},
fetch: globalThis.fetch,
}).catch(error => {
cb.onError(error.message)
abort.abort()
Expand All @@ -108,7 +109,24 @@ const isRunningInWebWorker =
typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope

if (isRunningInWebWorker) {
// HACK: @microsoft/fetch-event-source tries to call document.removeEventListener, which is not
// available in a worker.
;(self as any).document = { removeEventListener: () => {} }
// NOTE: If we need to add more hacks, or if this is janky, we should consider just setting
// `globalThis.window = globalThis` (see
// https://github.com/sourcegraph/cody/pull/4047#discussion_r1593823318).

;(self as any).document = {
// HACK: @microsoft/fetch-event-source tries to call document.removeEventListener, which is
// not available in a worker.
removeEventListener: () => {},

// HACK: web-tree-sitter tries to read window.document.currentScript, which fails if this is
// running in a Web Worker.
currentScript: null,
}
;(self as any).window = {
// HACK: @microsoft/fetch-event-source tries to call window.clearTimeout, which fails if this is
// running in a Web Worker.
clearTimeout: (...args: Parameters<typeof clearTimeout>) => clearTimeout(...args),

document: self.document,
}
}
2 changes: 1 addition & 1 deletion lib/shared/src/sourcegraph-api/graphql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ export class SourcegraphGraphQLAPIClient {
if (this.config.accessToken) {
headers.set('Authorization', `token ${this.config.accessToken}`)
}
if (this.anonymousUserID) {
if (this.anonymousUserID && !process.env.CODY_WEB_DONT_SET_SOME_HEADERS) {
headers.set('X-Sourcegraph-Actor-Anonymous-UID', this.anonymousUserID)
}

Expand Down
Loading

0 comments on commit 695d262

Please sign in to comment.