Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

cody: Sourcegraph backend #49514

Merged
merged 24 commits into from
Mar 21, 2023
Merged

cody: Sourcegraph backend #49514

merged 24 commits into from
Mar 21, 2023

Conversation

novoselrok
Copy link
Contributor

@novoselrok novoselrok commented Mar 16, 2023

Implements the new Sourcegraph backend for the Cody extension. Since it's a fairly large PR, I recommend reviewing commit by commit.

Test plan

  • Chatting and executing recipes should still work.
  • pnpm run build && pnpm run test:integration && pnpm run test:unit should be green.

App preview:

Check out the client app preview documentation to learn more.

Copy link
Contributor

@abeatrix abeatrix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm able to:

  • login with Sourcegraph Token (Super nice! 🎉 )
  • build and run extension
  • search without codebase
  • pass all the tests:
Cody extension activated
Setting up testing hooks
  End-to-end
    ✓ Cody registers some commands
no embeddings client for current codebase
    ✓ Explain Code (561ms)
  2 passing (584ms)
[main 2023-03-16T15:06:34.266Z] [UtilityProcess id: 1, type: extensionHost, pid: 18192]: waiting to exit...
[main 2023-03-16T15:06:34.267Z] [UtilityProcess id: 1, type: extensionHost, pid: 18192]: received exit event with code 0
[main 2023-03-16T15:06:34.267Z] Extension host with pid 18192 exited with code: 0, signal: unknown.
Exit code:   0
Done

  Prompt
    ✓ generates empty prompt with no messages


  1 passing (1ms)

bugs

Some bugs I found that might not have caused by changes introduced in this branch, but we should take a look at them later in other PRs.

  1. debug logs is empty

image

  1. Feedback buttons not working

image

  1. chat bubble not responsive
    cody-bug1

  2. chat input does not stay between views

cody-bug2

@novoselrok
Copy link
Contributor Author

@abeatrix

Re: bugs:

  1. I purposefully removed debugging because it was obstructing the migration. I'll add it back in a separate PR.
  2. The Sourcegraph backend does not support feedback, so I'll have to remove it entirely.
  3. Existing problem, we should create an issue for it.
  4. Existing problem, we should create an issue for it.

Copy link
Contributor

@dominiccooney dominiccooney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only partway through this but some thoughts inline. No need to block on me.

"default": "https://cody.sgdev.org",
"example": "https://cody.sgdev.org",
"description": "URL to the Cody embeddings API"
"default": "https://instance.sourcegraph.com",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is worth making this something invalid for a hostname, like instead of instance, to give a better hint that this needs to be set?

@@ -30,51 +30,50 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
private transcript: ChatMessage[] = []
private messageInProgress: ChatMessage | null = null

private closeConnectionInProgressPromise: Promise<() => void> | null = null
private prompt: Transcript
private stopCompletionInProgressCallback: (() => void) | null = null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phrasing of this is awkward, it reads to me like stop completion ... in the progress callback. But it's stopping the in-progress completion, or is it the callback to cause the in-progress completion to stop? It is the latter. What about cancelInProgressCompletion, cancelCompletion or something like that?

private contextType: 'embeddings' | 'keyword' | 'none' | 'blended',
private debug: boolean,
private secretStorage: SecretStorage
private prompt: Transcript,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this change, but I have been staring at Transcript a bit lately. We need more discipline over what Transcript, Chunk, and Message (displayed or actual) mean. Because we have a lot of overloading of "transcript" and "prompt" to mean, variously, sink for messages, factory for messages, array of messages; etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could not agree more. The class is getting out of control. I think that should be our next order of business: to refactor the Transcript class, decide how the context is constructed, and enforce it using unit tests.

this.accessToken = await this.getAccessToken()
this.wsclient = this.makeWSChatClient()
case 'endpoint': {
const accessToken = await getAccessToken(this.secretStorage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some duplication wrt the setup in the constructor, can we factor this out into one place?


this.prompt.addBotMessage(text)
this.messageInProgress = null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to put this pair into a little object so we always transition them together?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try that, but it might get awkward.

@@ -58,7 +75,13 @@ export class Transcript {
}

private async getCodebaseContextMessages(query: string): Promise<ContextMessage[]> {
const { needsCurrentFileContext, needsCodebaseContext } = await this.intentDetector.detect(query)
const intentOrError = await this.intentDetector.detect(query)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this diff, but we should experiment with a prompt architecture where we let Claude try to answer and push back on us if we need context, which we then provide. This will cut down the round trips for some queries. It will mean giving Claude some tools for requesting context which the plugin responds to.

There's also HIDE where we have to hallucinate answers and use the embedding for context fetching.

Rok Novosel added 2 commits March 17, 2023 07:56
…ript classes. Replace example instance url with an invalid url.
@sqs sqs added the cody label Mar 18, 2023
this.completionsEndpoint = `${instanceUrl}/.api/completions/stream`
}

private sendEvents(events: Event[], cb: CompletionCallbacks): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would a better name here be receiveEvents? If I'm understanding correctly, this function receives events from the server and calls the appropriate callback on the client side, rather than sending data to the server.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the events were streamed from the server, but we are forwarding them to the "client" function that invoked the stream method and supplied the callbacks. So an alternative name could be forwardEvents.

This is my proposal for a new Cody extension architecture. It might not
be the ideal architecture, but it's a huge improvement over the current
situation.

Here are the important concepts:

* `Interaction` is the atomic unit of the chat. It contains the human
question, the assistant response, and the context, if necessary. An
interaction can be converted to a prompt or a (chat) UI message.
* `Transcript` is a linear collection of `Interaction`s that can be
converted to a prompt or a full UI conversation. It also handles
limiting the prompt to a maximum length.
* **Everything is a recipe**, including the chat questions. A recipe
receives the necessary dependencies (chat input, editor, intent
detection, and codebase context) and constructs an `Interaction`. The
`ChatViewProvider` handles executing the recipe and adding the resulting
`Interaction` to the `Transcript`.
* Context fetching has been abstracted into the `CodebaseContext` class.
It handles switching between `embeddings` and `keyword` searching.
`blended` context type has not been implemented yet.
* Context messages are included for the last message only. See unit
tests for examples.
* Prompt structure is now enforced through unit tests.

## Test plan

* Chatting and executing recipes should still work.
* `pnpm run build && pnpm run test:integration && pnpm run test:unit`
should be green.

## App preview:

- [Web](https://sg-web-rn-cody-refactor-extension.onrender.com/search)

Check out the [client app preview
documentation](https://docs.sourcegraph.com/dev/how-to/client_pr_previews)
to learn more.
@novoselrok novoselrok merged commit 1b7ba64 into cody-main Mar 21, 2023
@novoselrok novoselrok deleted the rn/cody-sourcegraph-backend branch March 21, 2023 13:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants