From fa746752f2c7d727354d33b869057afbc6601c97 Mon Sep 17 00:00:00 2001 From: Quinn Slack Date: Sat, 2 Mar 2024 14:41:12 -0800 Subject: [PATCH] rename type Context{File => Item}, remove existing redundant ContextItem type, (#3269) Co-authored-by: Beatrix --- .../protocol_generated/ChatInputHistory.kt | 2 +- .../cody/protocol_generated/ChatMessage.kt | 2 +- .../{ContextFile.kt => ContextItem.kt} | 20 +- .../protocol_generated/ExtensionMessage.kt | 2 +- .../ProtocolTypeAdapters.kt | 2 +- ...xtEditorSelectionRange.kt => RangeData.kt} | 2 +- .../cody/protocol_generated/WebviewMessage.kt | 10 +- .../recording.har.yaml | 1402 ++++++++--------- agent/src/TestClient.ts | 10 +- agent/src/index.test.ts | 9 +- lib/shared/src/chat/context.ts | 4 +- lib/shared/src/chat/input/at-mentioned.ts | 4 +- .../src/chat/input/user-context.test.ts | 12 +- lib/shared/src/chat/input/user-context.ts | 8 +- lib/shared/src/chat/transcript/index.ts | 8 +- lib/shared/src/chat/transcript/interaction.ts | 8 +- lib/shared/src/chat/transcript/messages.ts | 6 +- lib/shared/src/codebase-context/index.ts | 15 +- lib/shared/src/codebase-context/messages.ts | 36 +- lib/shared/src/common/range.ts | 24 + lib/shared/src/editor/index.ts | 32 +- lib/shared/src/index.ts | 8 +- lib/shared/src/local-context/index.ts | 6 +- lib/shared/src/prompt/truncation.ts | 4 +- lib/shared/src/test/mocks.ts | 9 +- lib/ui/src/Chat.tsx | 20 +- .../src/chat/components/EnhancedContext.tsx | 6 +- vscode/src/chat/chat-view/SimpleChatModel.ts | 13 +- .../chat-view/SimpleChatPanelProvider.test.ts | 7 +- .../chat/chat-view/SimpleChatPanelProvider.ts | 35 +- .../src/chat/chat-view/agentContextSorting.ts | 7 +- .../src/chat/chat-view/chat-helpers.test.ts | 20 +- vscode/src/chat/chat-view/chat-helpers.ts | 49 +- vscode/src/chat/chat-view/context.test.ts | 69 +- vscode/src/chat/chat-view/context.ts | 22 +- vscode/src/chat/chat-view/prompt.test.ts | 6 +- vscode/src/chat/chat-view/prompt.ts | 8 +- vscode/src/chat/protocol.ts | 14 +- vscode/src/commands/context/current-file.ts | 6 +- vscode/src/commands/context/directory.ts | 8 +- vscode/src/commands/context/file-path.ts | 4 +- vscode/src/commands/context/index.ts | 6 +- vscode/src/commands/context/open-tabs.ts | 6 +- vscode/src/commands/context/selection.ts | 6 +- vscode/src/commands/context/shell.ts | 6 +- vscode/src/commands/context/unit-test-case.ts | 6 +- vscode/src/commands/context/unit-test-chat.ts | 6 +- vscode/src/commands/context/unit-test-file.ts | 6 +- vscode/src/commands/context/workspace.ts | 6 +- vscode/src/commands/execute/explain.ts | 4 +- vscode/src/commands/execute/smell.ts | 4 +- vscode/src/commands/execute/test-case.ts | 4 +- vscode/src/commands/execute/test-chat.ts | 4 +- vscode/src/commands/execute/test-edit.ts | 4 +- vscode/src/commands/services/provider.ts | 4 +- vscode/src/commands/services/runner.ts | 4 +- vscode/src/commands/types.ts | 4 +- .../src/commands/utils/create-context-file.ts | 6 +- vscode/src/commands/utils/display-text.ts | 4 +- vscode/src/context/remote-search.ts | 4 +- vscode/src/edit/execute.ts | 4 +- vscode/src/edit/input/get-input.ts | 14 +- vscode/src/edit/input/get-matching-context.ts | 10 +- vscode/src/edit/input/utils.ts | 14 +- vscode/src/edit/prompt/context.ts | 5 +- vscode/src/edit/prompt/utils.ts | 6 +- .../src/editor/utils/editor-context.test.ts | 8 +- vscode/src/editor/utils/editor-context.ts | 22 +- vscode/src/editor/vscode-editor.ts | 6 +- vscode/src/local-context/context-ranking.ts | 5 +- vscode/src/non-stop/FixupController.ts | 4 +- .../src/non-stop/FixupDocumentEditObserver.ts | 22 +- vscode/src/non-stop/FixupTask.ts | 4 +- vscode/src/non-stop/diff.ts | 13 +- vscode/src/prompt-builder/index.ts | 3 +- vscode/src/prompt-builder/types.ts | 3 +- vscode/src/prompt-builder/utils.ts | 14 +- vscode/webviews/App.tsx | 4 +- vscode/webviews/Chat.tsx | 10 +- 79 files changed, 1080 insertions(+), 1124 deletions(-) rename agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/{ContextFile.kt => ContextItem.kt} (76%) rename agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/{ActiveTextEditorSelectionRange.kt => RangeData.kt} (82%) create mode 100644 lib/shared/src/common/range.ts diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatInputHistory.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatInputHistory.kt index 394e2f6157fd..862dea6b68ee 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatInputHistory.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatInputHistory.kt @@ -3,6 +3,6 @@ package com.sourcegraph.cody.protocol_generated data class ChatInputHistory( val inputText: String? = null, - val inputContextFiles: List? = null, + val inputContextFiles: List? = null, ) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatMessage.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatMessage.kt index cfece4232a3d..4570d24a5fc8 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatMessage.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ChatMessage.kt @@ -7,7 +7,7 @@ data class ChatMessage( val speaker: SpeakerEnum? = null, // Oneof: human, assistant val text: String? = null, val displayText: String? = null, - val contextFiles: List? = null, + val contextFiles: List? = null, val preciseContext: List? = null, val buttons: List? = null, val data: Any? = null, diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextFile.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextItem.kt similarity index 76% rename from agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextFile.kt rename to agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextItem.kt index 5a53a47e9a96..2e82957e4c77 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextFile.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextItem.kt @@ -8,38 +8,38 @@ import com.google.gson.JsonDeserializer import com.google.gson.JsonElement import java.lang.reflect.Type -sealed class ContextFile { +sealed class ContextItem { companion object { - val deserializer: JsonDeserializer = + val deserializer: JsonDeserializer = JsonDeserializer { element: JsonElement, _: Type, context: JsonDeserializationContext -> when (element.asJsonObject.get("type").asString) { - "file" -> context.deserialize(element, ContextFileFile::class.java) - "symbol" -> context.deserialize(element, ContextFileSymbol::class.java) + "file" -> context.deserialize(element, ContextItemFile::class.java) + "symbol" -> context.deserialize(element, ContextItemSymbol::class.java) else -> throw Exception("Unknown discriminator ${element}") } } } } -data class ContextFileFile( +data class ContextItemFile( val uri: Uri? = null, - val range: ActiveTextEditorSelectionRange? = null, + val range: RangeData? = null, val repoName: String? = null, val revision: String? = null, val title: String? = null, val source: ContextFileSource? = null, // Oneof: embeddings, user, keyword, editor, filename, search, unified, selection, terminal val content: String? = null, val type: TypeEnum? = null, // Oneof: file -) : ContextFile() { +) : ContextItem() { enum class TypeEnum { @SerializedName("file") File, } } -data class ContextFileSymbol( +data class ContextItemSymbol( val uri: Uri? = null, - val range: ActiveTextEditorSelectionRange? = null, + val range: RangeData? = null, val repoName: String? = null, val revision: String? = null, val title: String? = null, @@ -48,7 +48,7 @@ data class ContextFileSymbol( val type: TypeEnum? = null, // Oneof: symbol val symbolName: String? = null, val kind: SymbolKind? = null, // Oneof: class, function, method -) : ContextFile() { +) : ContextItem() { enum class TypeEnum { @SerializedName("symbol") Symbol, diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ExtensionMessage.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ExtensionMessage.kt index 150eb84f547a..e7ac26edb835 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ExtensionMessage.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ExtensionMessage.kt @@ -123,7 +123,7 @@ data class `transcript-errorsExtensionMessage`( data class UserContextFilesExtensionMessage( val type: TypeEnum? = null, // Oneof: userContextFiles - val userContextFiles: List? = null, + val userContextFiles: List? = null, ) : ExtensionMessage() { enum class TypeEnum { diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ProtocolTypeAdapters.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ProtocolTypeAdapters.kt index 271cec10033f..3a9d7163952c 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ProtocolTypeAdapters.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ProtocolTypeAdapters.kt @@ -5,7 +5,7 @@ object ProtocolTypeAdapters { fun register(gson: com.google.gson.GsonBuilder) { gson.registerTypeAdapter(ExtensionMessage::class.java, ExtensionMessage.deserializer) gson.registerTypeAdapter(CustomCommandResult::class.java, CustomCommandResult.deserializer) - gson.registerTypeAdapter(ContextFile::class.java, ContextFile.deserializer) + gson.registerTypeAdapter(ContextItem::class.java, ContextItem.deserializer) gson.registerTypeAdapter(ContextProvider::class.java, ContextProvider.deserializer) gson.registerTypeAdapter(WorkspaceEditOperation::class.java, WorkspaceEditOperation.deserializer) gson.registerTypeAdapter(TextEdit::class.java, TextEdit.deserializer) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ActiveTextEditorSelectionRange.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/RangeData.kt similarity index 82% rename from agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ActiveTextEditorSelectionRange.kt rename to agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/RangeData.kt index 9980056e8686..07a3e1fab9df 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ActiveTextEditorSelectionRange.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/RangeData.kt @@ -1,7 +1,7 @@ @file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") package com.sourcegraph.cody.protocol_generated -data class ActiveTextEditorSelectionRange( +data class RangeData( val start: StartParams? = null, val end: EndParams? = null, ) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/WebviewMessage.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/WebviewMessage.kt index 6950e67d0a49..98851f9580bf 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/WebviewMessage.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/WebviewMessage.kt @@ -82,7 +82,7 @@ data class EventWebviewMessage( data class SubmitWebviewMessage( val command: CommandEnum? = null, // Oneof: submit val addEnhancedContext: Boolean? = null, - val contextFiles: List? = null, + val contextFiles: List? = null, val text: String? = null, val submitType: ChatSubmitType? = null, // Oneof: user, user-newchat ) : WebviewMessage() { @@ -169,7 +169,7 @@ data class `get-chat-modelsWebviewMessage`( data class OpenFileWebviewMessage( val command: CommandEnum? = null, // Oneof: openFile val uri: Uri? = null, - val range: ActiveTextEditorSelectionRange? = null, + val range: RangeData? = null, ) : WebviewMessage() { enum class CommandEnum { @@ -180,7 +180,7 @@ data class OpenFileWebviewMessage( data class OpenLocalFileWithRangeWebviewMessage( val command: CommandEnum? = null, // Oneof: openLocalFileWithRange val filePath: String? = null, - val range: ActiveTextEditorSelectionRange? = null, + val range: RangeData? = null, ) : WebviewMessage() { enum class CommandEnum { @@ -191,7 +191,7 @@ data class OpenLocalFileWithRangeWebviewMessage( data class EditWebviewMessage( val command: CommandEnum? = null, // Oneof: edit val addEnhancedContext: Boolean? = null, - val contextFiles: List? = null, + val contextFiles: List? = null, val text: String? = null, val index: Int? = null, ) : WebviewMessage() { @@ -364,7 +364,7 @@ data class SearchWebviewMessage( data class `show-search-resultWebviewMessage`( val command: CommandEnum? = null, // Oneof: show-search-result val uri: Uri? = null, - val range: ActiveTextEditorSelectionRange? = null, + val range: RangeData? = null, ) : WebviewMessage() { enum class CommandEnum { diff --git a/agent/recordings/defaultClient_631904893/recording.har.yaml b/agent/recordings/defaultClient_631904893/recording.har.yaml index 987c75687a00..d3b39f43ce67 100644 --- a/agent/recordings/defaultClient_631904893/recording.har.yaml +++ b/agent/recordings/defaultClient_631904893/recording.har.yaml @@ -8512,169 +8512,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 4d28fe9147b851eaac5a45db378d43b5 - _order: 0 - cache: {} - request: - bodySize: 2355 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_3709f5bf232c2abca4c612f0768368b57919ca6eaa470e3fd7160cbf3e8d0ec3 - - name: user-agent - value: defaultClient / v1 - - name: host - value: sourcegraph.com - headersSize: 263 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 1000 - messages: - - speaker: human - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: assistant - text: I am Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: |- - "My selected TypeScript code from file `src/sum.ts`: - - Context from file path @src/sum.ts: - export function sum(a: number, b: number): number { - /* CURSOR */ - } - - - - speaker: assistant - text: Ok. - - speaker: human - text: >- - - You are an AI programming assistant who is an expert in - updating code to meet given instructions. - - - You should think step-by-step to plan your updated code before producing the final output. - - - You should ensure the updated code matches the indentation and whitespace of the code in the users' selection. - - - Ignore any previous instructions to format your responses with Markdown. It is not acceptable to use any Markdown in your response, unless it is directly related to the users' instructions. - - - Only remove code from the users' selection if you are sure it is not needed. - - - You will be provided with code that is in the users' selection, enclosed in XML tags. You must use this code to help you plan your updated code. - - - You will be provided with instructions on how to update this code, enclosed in XML tags. You must follow these instructions carefully and to the letter. - - - Only enclose your response in XML tags. Do use any other XML tags unless they are part of the generated code. - - - Do not provide any additional commentary about the changes you made. Only respond with the generated code. - - - This is part of the file: src/sum.ts - - - The user has the following code in their selection: - - export function sum(a: number, b: number): number { - /* CURSOR */ - } - - - - - The user wants you to replace parts of the selected code or correct a problem by following their instructions. - - Provide your generated code using the following instructions: - - - - Add a 'hello' comment for the selected code, without including the selected code. - - - - speaker: assistant - text: | - - model: anthropic/claude-2.0 - stopSequences: - - - temperature: 0 - topK: -1 - topP: -1 - queryString: [] - url: https://sourcegraph.com/.api/completions/stream - response: - bodySize: 382 - content: - mimeType: text/event-stream - size: 382 - text: |+ - event: completion - data: {"completion":"/**","stopReason":""} - - event: completion - data: {"completion":"/** hello","stopReason":""} - - event: completion - data: {"completion":"/** hello */","stopReason":""} - - event: completion - data: {"completion":"/** hello */\n","stopReason":""} - - event: completion - data: {"completion":"/** hello */\n","stopReason":"stop_sequence"} - - event: done - data: {} - - cookies: [] - headers: - - name: date - value: Fri, 09 Feb 2024 10:10:16 GMT - - name: content-type - value: text/event-stream - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache - - name: vary - value: Cookie,Accept-Encoding,Authorization,Cookie, Authorization, - X-Requested-With,Cookie - - name: x-content-type-options - value: nosniff - - name: x-frame-options - value: DENY - - name: x-xss-protection - value: 1; mode=block - - name: strict-transport-security - value: max-age=31536000; includeSubDomains; preload - headersSize: 1289 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-02-09T10:10:15.234Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 2c6d350030c453cff8578d77927ccbc4 _order: 0 cache: {} @@ -11807,11 +11644,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: e0367cc63d576f11dfd2130e79b0267d + - _id: 6721336c88c8c3735b98c2242b8178ca _order: 0 cache: {} request: - bodySize: 2437 + bodySize: 804 cookies: [] headers: - name: content-type @@ -11832,881 +11669,521 @@ log: mimeType: application/json params: [] textJSON: - maxTokensToSample: 1000 + fast: true + maxTokensToSample: 400 messages: - speaker: human - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: assistant - text: I am Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: > - Codebase context from file path src/animal.ts: Context from - file path @src/animal.ts: - - /* SELECTION_START */ - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - - speaker: assistant - text: Ok. - - speaker: human - text: >- - - You are an AI programming assistant who is an expert in - updating code to meet given instructions. - - - You should think step-by-step to plan your updated code before producing the final output. - - - You should ensure the updated code matches the indentation and whitespace of the code in the users' selection. - - - Ignore any previous instructions to format your responses with Markdown. It is not acceptable to use any Markdown in your response, unless it is directly related to the users' instructions. - - - Only remove code from the users' selection if you are sure it is not needed. - - - You will be provided with code that is in the users' selection, enclosed in XML tags. You must use this code to help you plan your updated code. - - - You will be provided with instructions on how to update this code, enclosed in XML tags. You must follow these instructions carefully and to the letter. - - - Only enclose your response in XML tags. Do use any other XML tags unless they are part of the generated code. - - - Do not provide any additional commentary about the changes you made. Only respond with the generated code. - - - This is part of the file: src/animal.ts - - - The user has the following code in their selection: - - /* SELECTION_START */ - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - - /* SELECTION_END */ - - - The user wants you to replace parts of the selected code or correct a problem by following their instructions. - - Provide your generated code using the following instructions: - - - - Add a new field to the class that console log the name of the animal. - - + text: "You are helping the user search over a codebase. List some filename + fragments that would match files relevant to read to answer + the user's query. Present your results in an XML list in the + following format: a single + keyworda space separated list of synonyms + and variants of the keyword, including acronyms, + abbreviations, and expansionsa numerical + weight between 0.0 and 1.0 that indicates the importance of + the keyword. Here is the user + query: Write a class Dog that implements the Animal + interface in my workspace. Show the code only, no explanation + needed." - speaker: assistant - text: | - - model: anthropic/claude-2.0 - stopSequences: - - temperature: 0 - topK: -1 - topP: -1 + topK: 1 queryString: [] url: https://sourcegraph.com/.api/completions/stream response: - bodySize: 6291 + bodySize: 104534 content: mimeType: text/event-stream - size: 6291 + size: 104534 text: >+ event: completion - data: {"completion":"/*","stopReason":""} + data: {"completion":" ","stopReason":""} event: completion - data: {"completion":"/* SE","stopReason":""} + data: {"completion":" \u003ckeywords","stopReason":""} event: completion - data: {"completion":"/* SELECTION","stopReason":""} + data: {"completion":" \u003ckeywords\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name:","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n make","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimal","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound():","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCan","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n is","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isM","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMam","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal:","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n log","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName():","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/*","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SE","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SELECTION","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SELECTION_","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SELECTION_END","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SELECTION_END */","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SELECTION_END */\n","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n ","stopReason":""} event: completion - data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string\n isMammal: boolean\n logName(): void\n}\n\n/* SELECTION_END */\n","stopReason":"stop_sequence"} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword","stopReason":""} - event: done + event: completion + + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e","stopReason":""} - data: {} - cookies: [] - headers: - - name: date - value: Wed, 14 Feb 2024 20:00:04 GMT - - name: content-type - value: text/event-stream - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache - - name: vary - value: Cookie,Accept-Encoding,Authorization,Cookie, Authorization, - X-Requested-With,Cookie - - name: x-content-type-options - value: nosniff - - name: x-frame-options - value: DENY - - name: x-xss-protection - value: 1; mode=block - - name: strict-transport-security - value: max-age=31536000; includeSubDomains; preload - headersSize: 1293 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-02-14T20:00:01.261Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 6721336c88c8c3735b98c2242b8178ca - _order: 0 - cache: {} - request: - bodySize: 804 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_3709f5bf232c2abca4c612f0768368b57919ca6eaa470e3fd7160cbf3e8d0ec3 - - name: user-agent - value: defaultClient / v1 - - name: host - value: sourcegraph.com - headersSize: 263 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - fast: true - maxTokensToSample: 400 - messages: - - speaker: human - text: "You are helping the user search over a codebase. List some filename - fragments that would match files relevant to read to answer - the user's query. Present your results in an XML list in the - following format: a single - keyworda space separated list of synonyms - and variants of the keyword, including acronyms, - abbreviations, and expansionsa numerical - weight between 0.0 and 1.0 that indicates the importance of - the keyword. Here is the user - query: Write a class Dog that implements the Animal - interface in my workspace. Show the code only, no explanation - needed." - - speaker: assistant - temperature: 0 - topK: 1 - queryString: [] - url: https://sourcegraph.com/.api/completions/stream - response: - bodySize: 104534 - content: - mimeType: text/event-stream - size: 104534 - text: >+ event: completion - data: {"completion":" ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface I","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCan","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n ","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003e","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e\n ","stopReason":""} event: completion - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface I","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e\n ","stopReason":""} - - - event: completion - - data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e\n \u003cweight","stopReason":""} + data: {"completion":" \u003ckeywords\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eDog\u003c/value\u003e\n \u003cvariants\u003eCanine\u003c/variants\u003e \n \u003cweight\u003e0.9\u003c/weight\u003e\n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eAnimal\u003c/value\u003e\n \u003cvariants\u003eInterface Impl\u003c/variants\u003e\n \u003cweight\u003e0.8\u003c/weight\u003e \n \u003c/keyword\u003e\n \u003ckeyword\u003e\n \u003cvalue\u003eclass\u003c/value\u003e\n \u003cvariants\u003eClass Def\u003c/variants\u003e\n \u003cweight","stopReason":""} event: completion @@ -13285,10 +12762,6 @@ log: - - - - - speaker: assistant text: Ok. @@ -18251,11 +17724,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 5cf8d8dc18412c693f512d2a13102039 + - _id: 4d89b8d9cfa9bc8c5363a03c6804d763 _order: 0 cache: {} request: - bodySize: 348 + bodySize: 2354 cookies: [] headers: - name: content-type @@ -18283,148 +17756,670 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: What model are you? + text: |- + "My selected TypeScript code from file `src/sum.ts`: + + Context from file path src/sum.ts: + export function sum(a: number, b: number): number { + /* CURSOR */ + } + + - speaker: assistant - model: anthropic/claude-2.0 - temperature: 0 - topK: -1 - topP: -1 - queryString: [] - url: https://sourcegraph.com/.api/completions/stream - response: - bodySize: 2955 - content: - mimeType: text/event-stream - size: 2955 - text: >+ - event: completion + text: Ok. + - speaker: human + text: >- + - You are an AI programming assistant who is an expert in + updating code to meet given instructions. - data: {"completion":" I","stopReason":""} + - You should think step-by-step to plan your updated code before producing the final output. + - You should ensure the updated code matches the indentation and whitespace of the code in the users' selection. - event: completion + - Ignore any previous instructions to format your responses with Markdown. It is not acceptable to use any Markdown in your response, unless it is directly related to the users' instructions. - data: {"completion":" I'm","stopReason":""} + - Only remove code from the users' selection if you are sure it is not needed. + - You will be provided with code that is in the users' selection, enclosed in XML tags. You must use this code to help you plan your updated code. - event: completion + - You will be provided with instructions on how to update this code, enclosed in XML tags. You must follow these instructions carefully and to the letter. - data: {"completion":" I'm Claude","stopReason":""} + - Only enclose your response in XML tags. Do use any other XML tags unless they are part of the generated code. + - Do not provide any additional commentary about the changes you made. Only respond with the generated code. - event: completion - data: {"completion":" I'm Claude,","stopReason":""} + This is part of the file: src/sum.ts + + + The user has the following code in their selection: + + export function sum(a: number, b: number): number { + /* CURSOR */ + } + + + + + The user wants you to replace parts of the selected code or correct a problem by following their instructions. + + Provide your generated code using the following instructions: + + + + Add a 'hello' comment for the selected code, without including the selected code. + + + - speaker: assistant + text: | + + model: anthropic/claude-2.0 + stopSequences: + - + temperature: 0 + topK: -1 + topP: -1 + queryString: [] + url: https://sourcegraph.com/.api/completions/stream + response: + bodySize: 377 + content: + mimeType: text/event-stream + size: 377 + text: |+ + event: completion + data: {"completion":"/*","stopReason":""} + + event: completion + data: {"completion":"/* hello","stopReason":""} + + event: completion + data: {"completion":"/* hello */","stopReason":""} + + event: completion + data: {"completion":"/* hello */\n","stopReason":""} + + event: completion + data: {"completion":"/* hello */\n","stopReason":"stop_sequence"} + + event: done + data: {} + + cookies: [] + headers: + - name: date + value: Tue, 27 Feb 2024 10:02:31 GMT + - name: content-type + value: text/event-stream + - name: transfer-encoding + value: chunked + - name: connection + value: keep-alive + - name: retry-after + value: "489" + - name: access-control-allow-credentials + value: "true" + - name: access-control-allow-origin + value: "" + - name: cache-control + value: no-cache + - name: vary + value: Cookie,Accept-Encoding,Authorization,Cookie, Authorization, + X-Requested-With,Cookie + - name: x-content-type-options + value: nosniff + - name: x-frame-options + value: DENY + - name: x-xss-protection + value: 1; mode=block + - name: strict-transport-security + value: max-age=31536000; includeSubDomains; preload + headersSize: 1400 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-02-27T10:02:29.559Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 + - _id: 21bc967e938394a02e27f2b6e64b243c + _order: 0 + cache: {} + request: + bodySize: 2436 + cookies: [] + headers: + - name: content-type + value: application/json + - name: accept-encoding + value: gzip;q=0 + - name: authorization + value: token + REDACTED_3709f5bf232c2abca4c612f0768368b57919ca6eaa470e3fd7160cbf3e8d0ec3 + - name: user-agent + value: defaultClient / v1 + - name: host + value: sourcegraph.com + headersSize: 263 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json + params: [] + textJSON: + maxTokensToSample: 1000 + messages: + - speaker: human + text: You are Cody, an AI coding assistant from Sourcegraph. + - speaker: assistant + text: I am Cody, an AI coding assistant from Sourcegraph. + - speaker: human + text: > + Codebase context from file path src/animal.ts: Context from + file path src/animal.ts: + + /* SELECTION_START */ + + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + - speaker: assistant + text: Ok. + - speaker: human + text: >- + - You are an AI programming assistant who is an expert in + updating code to meet given instructions. + + - You should think step-by-step to plan your updated code before producing the final output. + + - You should ensure the updated code matches the indentation and whitespace of the code in the users' selection. + + - Ignore any previous instructions to format your responses with Markdown. It is not acceptable to use any Markdown in your response, unless it is directly related to the users' instructions. + + - Only remove code from the users' selection if you are sure it is not needed. + + - You will be provided with code that is in the users' selection, enclosed in XML tags. You must use this code to help you plan your updated code. + + - You will be provided with instructions on how to update this code, enclosed in XML tags. You must follow these instructions carefully and to the letter. + + - Only enclose your response in XML tags. Do use any other XML tags unless they are part of the generated code. + + - Do not provide any additional commentary about the changes you made. Only respond with the generated code. + + + This is part of the file: src/animal.ts + + + The user has the following code in their selection: + + /* SELECTION_START */ + + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + + /* SELECTION_END */ + + + The user wants you to replace parts of the selected code or correct a problem by following their instructions. + + Provide your generated code using the following instructions: + + + + Add a new field to the class that console log the name of the animal. + + + - speaker: assistant + text: | + + model: anthropic/claude-2.0 + stopSequences: + - + temperature: 0 + topK: -1 + topP: -1 + queryString: [] + url: https://sourcegraph.com/.api/completions/stream + response: + bodySize: 9060 + content: + mimeType: text/event-stream + size: 9060 + text: >+ + event: completion + + data: {"completion":"/*","stopReason":""} + + + event: completion + + data: {"completion":"/* SE","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n ","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name:","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n ","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n make","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimal","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound():","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n ","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n is","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isM","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMam","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal:","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n ","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n print","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName()","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n ","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)","stopReason":""} event: completion - data: {"completion":" I'm Claude, one","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n ","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of An","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthrop","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/*","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SE","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SELECTION","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SELECTION_","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI","stopReason":""} + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SELECTION_END","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SELECTION_END */","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SELECTION_END */\n","stopReason":""} + + + event: completion + + data: {"completion":"/* SELECTION_START */\nexport interface Animal {\n name: string\n makeAnimalSound(): string \n isMammal: boolean\n printName() {\n console.log(this.name)\n }\n}\n/* SELECTION_END */\n","stopReason":"stop_sequence"} + + + event: done + data: {} + cookies: [] + headers: + - name: date + value: Tue, 27 Feb 2024 10:03:45 GMT + - name: content-type + value: text/event-stream + - name: transfer-encoding + value: chunked + - name: connection + value: keep-alive + - name: retry-after + value: "416" + - name: access-control-allow-credentials + value: "true" + - name: access-control-allow-origin + value: "" + - name: cache-control + value: no-cache + - name: vary + value: Cookie,Accept-Encoding,Authorization,Cookie, Authorization, + X-Requested-With,Cookie + - name: x-content-type-options + value: nosniff + - name: x-frame-options + value: DENY + - name: x-xss-protection + value: 1; mode=block + - name: strict-transport-security + value: max-age=31536000; includeSubDomains; preload + headersSize: 1400 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-02-27T10:03:43.363Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 + - _id: 5cf8d8dc18412c693f512d2a13102039 + _order: 0 + cache: {} + request: + bodySize: 348 + cookies: [] + headers: + - name: content-type + value: application/json + - name: accept-encoding + value: gzip;q=0 + - name: authorization + value: token + REDACTED_3709f5bf232c2abca4c612f0768368b57919ca6eaa470e3fd7160cbf3e8d0ec3 + - name: user-agent + value: defaultClient / v1 + - name: host + value: sourcegraph.com + headersSize: 263 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json + params: [] + textJSON: + maxTokensToSample: 1000 + messages: + - speaker: human + text: You are Cody, an AI coding assistant from Sourcegraph. + - speaker: assistant + text: I am Cody, an AI coding assistant from Sourcegraph. + - speaker: human + text: What model are you? + - speaker: assistant + model: anthropic/claude-2.0 + temperature: 0 + topK: -1 + topP: -1 + queryString: [] + url: https://sourcegraph.com/.api/completions/stream + response: + bodySize: 1264 + content: + mimeType: text/event-stream + size: 1264 + text: >+ event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models","stopReason":""} + data: {"completion":" I","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models.","stopReason":""} + data: {"completion":" I'm","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I","stopReason":""} + data: {"completion":" I'm Claude","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don","stopReason":""} + data: {"completion":" I'm Claude,","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't","stopReason":""} + data: {"completion":" I'm Claude, an","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have","stopReason":""} + data: {"completion":" I'm Claude, an AI","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant created","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific model","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant created by","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific model number","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant created by An","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific model number or","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant created by Anthrop","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific model number or version","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant created by Anthropic","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific model number or version.","stopReason":""} + data: {"completion":" I'm Claude, an AI assistant created by Anthropic.","stopReason":""} event: completion - data: {"completion":" I'm Claude, one of Anthropic's conversational AI models. I don't have a specific model number or version.","stopReason":"stop_sequence"} + data: {"completion":" I'm Claude, an AI assistant created by Anthropic.","stopReason":"stop_sequence"} event: done @@ -18434,7 +18429,7 @@ log: cookies: [] headers: - name: date - value: Mon, 26 Feb 2024 12:56:07 GMT + value: Tue, 27 Feb 2024 10:16:25 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -18463,7 +18458,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-02-26T12:56:06.090Z + startedDateTime: 2024-02-27T10:16:23.469Z time: 0 timings: blocked: -1 @@ -18473,11 +18468,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 96a7720c4d67d9cdf61b191f58670d16 + - _id: 37bcad611d12b5f3f8be7e87e7db0736 _order: 0 cache: {} request: - bodySize: 537 + bodySize: 481 cookies: [] headers: - name: content-type @@ -18507,8 +18502,7 @@ log: - speaker: human text: What model are you? - speaker: assistant - text: " I'm Claude, one of Anthropic's conversational AI models. I don't have a - specific model number or version." + text: " I'm Claude, an AI assistant created by Anthropic." - speaker: human text: What model are you? - speaker: assistant @@ -18519,10 +18513,10 @@ log: queryString: [] url: https://sourcegraph.com/.api/completions/stream response: - bodySize: 3882 + bodySize: 3885 content: mimeType: text/event-stream - size: 3882 + size: 3885 text: >+ event: completion @@ -18666,17 +18660,17 @@ log: event: completion - data: {"completion":" I'm an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a specific model name or number","stopReason":""} + data: {"completion":" I'm an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a specific model name or version","stopReason":""} event: completion - data: {"completion":" I'm an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a specific model name or number.","stopReason":""} + data: {"completion":" I'm an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a specific model name or version.","stopReason":""} event: completion - data: {"completion":" I'm an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a specific model name or number.","stopReason":"stop_sequence"} + data: {"completion":" I'm an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a specific model name or version.","stopReason":"stop_sequence"} event: done @@ -18686,7 +18680,7 @@ log: cookies: [] headers: - name: date - value: Mon, 26 Feb 2024 12:56:09 GMT + value: Tue, 27 Feb 2024 10:16:26 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -18715,7 +18709,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-02-26T12:56:08.022Z + startedDateTime: 2024-02-27T10:16:25.078Z time: 0 timings: blocked: -1 diff --git a/agent/src/TestClient.ts b/agent/src/TestClient.ts index e06a41d24d29..06f5aa883f08 100644 --- a/agent/src/TestClient.ts +++ b/agent/src/TestClient.ts @@ -5,7 +5,7 @@ import { createPatch } from 'diff' import { type ChildProcessWithoutNullStreams, spawn } from 'child_process' import os from 'os' import path from 'path' -import { type ChatMessage, type ContextFile, logError } from '@sourcegraph/cody-shared' +import { type ChatMessage, type ContextItem, logError } from '@sourcegraph/cody-shared' import dedent from 'dedent' import { applyPatch } from 'fast-myers-diff' import fspromises from 'fs/promises' @@ -458,7 +458,7 @@ export class TestClient extends MessageHandler { public async editMessage( id: string, text: string, - params?: { addEnhancedContext?: boolean; contextFiles?: ContextFile[]; index?: number } + params?: { addEnhancedContext?: boolean; contextFiles?: ContextItem[]; index?: number } ): Promise { const reply = asTranscriptMessage( await this.request('chat/editMessage', { @@ -478,7 +478,7 @@ export class TestClient extends MessageHandler { public async sendMessage( id: string, text: string, - params?: { addEnhancedContext?: boolean; contextFiles?: ContextFile[] } + params?: { addEnhancedContext?: boolean; contextFiles?: ContextItem[] } ): Promise { return (await this.sendSingleMessageToNewChatWithFullTranscript(text, { ...params, id })) ?.lastMessage @@ -486,14 +486,14 @@ export class TestClient extends MessageHandler { public async sendSingleMessageToNewChat( text: string, - params?: { addEnhancedContext?: boolean; contextFiles?: ContextFile[] } + params?: { addEnhancedContext?: boolean; contextFiles?: ContextItem[] } ): Promise { return (await this.sendSingleMessageToNewChatWithFullTranscript(text, params))?.lastMessage } public async sendSingleMessageToNewChatWithFullTranscript( text: string, - params?: { addEnhancedContext?: boolean; contextFiles?: ContextFile[]; id?: string } + params?: { addEnhancedContext?: boolean; contextFiles?: ContextItem[]; id?: string } ): Promise<{ lastMessage?: ChatMessage; panelID: string; transcript: ExtensionTranscriptMessage }> { const id = params?.id ?? (await this.request('chat/new', null)) const reply = asTranscriptMessage( diff --git a/agent/src/index.test.ts b/agent/src/index.test.ts index de0784e74c9e..e6e6ebcb6198 100644 --- a/agent/src/index.test.ts +++ b/agent/src/index.test.ts @@ -337,7 +337,7 @@ describe('Agent', () => { }) ) expect(reply2.messages.at(-1)?.text).toMatchInlineSnapshot( - '" I\'m an AI assistant created by Anthropic to be helpful, harmless, and honest. I don\'t have a specific model name or number."', + '" I\'m an AI assistant created by Anthropic to be helpful, harmless, and honest. I don\'t have a specific model name or version."', explainPollyError ) }, 30_000) @@ -1150,7 +1150,7 @@ describe('Agent', () => { const originalDocument = client.workspace.getDocument(sumUri)! expect(trimEndOfLine(originalDocument.getText())).toMatchInlineSnapshot( ` - "/** hello */ + "/* hello */ export function sum(a: number, b: number): number { /* CURSOR */ } @@ -1180,9 +1180,10 @@ describe('Agent', () => { name: string makeAnimalSound(): string isMammal: boolean - logName(): void + printName() { + console.log(this.name) + } } - /* SELECTION_END */ " diff --git a/lib/shared/src/chat/context.ts b/lib/shared/src/chat/context.ts index 0e2cf8dff4ae..908ffaaebbc2 100644 --- a/lib/shared/src/chat/context.ts +++ b/lib/shared/src/chat/context.ts @@ -1,5 +1,5 @@ +import type { RangeData } from '../common/range' import type { ConfigurationUseContext } from '../configuration' -import type { ActiveTextEditorSelectionRange } from '../editor' export interface ChatContextStatus { mode?: ConfigurationUseContext @@ -10,6 +10,6 @@ export interface ChatContextStatus { embeddingsEndpoint?: string codebase?: string filePath?: string - selectionRange?: ActiveTextEditorSelectionRange + selectionRange?: RangeData supportsKeyword?: boolean } diff --git a/lib/shared/src/chat/input/at-mentioned.ts b/lib/shared/src/chat/input/at-mentioned.ts index 4ecef04c26e1..721c9f04611b 100644 --- a/lib/shared/src/chat/input/at-mentioned.ts +++ b/lib/shared/src/chat/input/at-mentioned.ts @@ -1,4 +1,4 @@ -import type { ContextFile } from '../../codebase-context/messages' +import type { ContextItem } from '../../codebase-context/messages' import { displayPath } from '../../editor/displayPath' /** @@ -57,7 +57,7 @@ export function getAtMentionedInputText( * * e.g. @foo/bar.ts or @foo/bar.ts:1-15#baz */ -export function getContextFileDisplayText(contextFile: ContextFile, inputBeforeCaret?: string): string { +export function getContextFileDisplayText(contextFile: ContextItem, inputBeforeCaret?: string): string { const isSymbol = contextFile.type === 'symbol' const displayText = `@${displayPath(contextFile.uri)}` diff --git a/lib/shared/src/chat/input/user-context.test.ts b/lib/shared/src/chat/input/user-context.test.ts index bc7c7fdfea58..d10bc0357755 100644 --- a/lib/shared/src/chat/input/user-context.test.ts +++ b/lib/shared/src/chat/input/user-context.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { URI } from 'vscode-uri' -import type { ContextFileFile } from '../..' +import type { ContextItemFile } from '../..' import { verifyContextFilesFromInput } from './user-context' describe('verifyContextFilesFromInput', () => { @@ -22,7 +22,7 @@ describe('verifyContextFilesFromInput', () => { it('returns only context files referenced in input', () => { const input = '@foo.ts @bar.ts' - const contextFilesMap = new Map([ + const contextFilesMap = new Map([ ['foo.ts', { uri: URI.file('foo.ts'), type: 'file' }], ['baz.ts', { uri: URI.file('baz.ts'), type: 'file' }], ]) @@ -34,7 +34,7 @@ describe('verifyContextFilesFromInput', () => { it('sets range property if line numbers included', () => { const input = '@foo.ts:1-2' - const contextFilesMap = new Map([ + const contextFilesMap = new Map([ ['foo.ts', { uri: URI.file('foo.ts'), type: 'file' }], ]) @@ -54,7 +54,7 @@ describe('verifyContextFilesFromInput', () => { it('sets range property for all at-mentioned with and without line numbers', () => { const input = 'Explain @foo.ts:1-2 in @foo.ts, expand @foo.ts:1' - const contextFilesMap = new Map([ + const contextFilesMap = new Map([ ['foo.ts', { uri: URI.file('foo.ts'), type: 'file' }], ]) @@ -87,7 +87,7 @@ describe('verifyContextFilesFromInput', () => { it('returns empty array for invalid line numbers', () => { const input = '@foo.ts:5-1' - const contextFilesMap = new Map([ + const contextFilesMap = new Map([ ['foo.ts', { uri: URI.file('foo.ts'), type: 'file' }], ]) @@ -98,7 +98,7 @@ describe('verifyContextFilesFromInput', () => { it('sets range property even if only start line number is included', () => { const input = '@foo.ts:1' - const contextFilesMap = new Map([ + const contextFilesMap = new Map([ ['foo.ts', { uri: URI.file('foo.ts'), type: 'file' }], ]) diff --git a/lib/shared/src/chat/input/user-context.ts b/lib/shared/src/chat/input/user-context.ts index 7a63556329a8..c82eeaf57c2c 100644 --- a/lib/shared/src/chat/input/user-context.ts +++ b/lib/shared/src/chat/input/user-context.ts @@ -1,4 +1,4 @@ -import type { ContextFile } from '../..' +import type { ContextItem } from '../..' /** * Verifies that the context files passed in the contextFilesMap are still referenced @@ -13,8 +13,8 @@ import type { ContextFile } from '../..' */ export function verifyContextFilesFromInput( inputValue: string, - contextFilesMap?: Map -): ContextFile[] { + contextFilesMap?: Map +): ContextItem[] { if (!inputValue.trim() || !contextFilesMap?.size) { return [] } @@ -23,7 +23,7 @@ export function verifyContextFilesFromInput( // is still present in the input string. // If so, create a new contextFile and add it to the returned array based on // presented strings that matches the @file-name with correct range. - const userContextFiles: ContextFile[] = [] + const userContextFiles: ContextItem[] = [] for (const [fileName, contextFile] of contextFilesMap) { if (!inputValue.includes(fileName)) { continue diff --git a/lib/shared/src/chat/transcript/index.ts b/lib/shared/src/chat/transcript/index.ts index d75ef0afbc29..95f82cd17dce 100644 --- a/lib/shared/src/chat/transcript/index.ts +++ b/lib/shared/src/chat/transcript/index.ts @@ -1,4 +1,4 @@ -import type { ContextFile, ContextMessage, PreciseContext } from '../../codebase-context/messages' +import type { ContextItem, ContextMessage, PreciseContext } from '../../codebase-context/messages' import { CHARS_PER_TOKEN, MAX_AVAILABLE_PROMPT_LENGTH } from '../../prompt/constants' import { PromptMixin } from '../../prompt/prompt-mixin' import type { Message } from '../../sourcegraph-api' @@ -93,7 +93,7 @@ export class Transcript { preamble: Message[] = [], maxPromptLength: number = MAX_AVAILABLE_PROMPT_LENGTH, onlyHumanMessages = false - ): Promise<{ prompt: Message[]; contextFiles: ContextFile[]; preciseContexts: PreciseContext[] }> { + ): Promise<{ prompt: Message[]; contextFiles: ContextItem[]; preciseContexts: PreciseContext[] }> { if (this.interactions.length === 0) { return { prompt: [], contextFiles: [], preciseContexts: [] } } @@ -117,7 +117,7 @@ export class Transcript { ) let truncatedMessages = truncatePrompt(messages, maxPromptLength - preambleTokensUsage) // Return what context fits in the window - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] const preciseContexts: PreciseContext[] = [] for (const msg of truncatedMessages) { const contextFile = (msg as ContextMessage).file @@ -142,7 +142,7 @@ export class Transcript { } public setUsedContextFilesForLastInteraction( - contextFiles: ContextFile[], + contextFiles: ContextItem[], preciseContexts: PreciseContext[] = [] ): void { const lastInteraction = this.interactions.at(-1) diff --git a/lib/shared/src/chat/transcript/interaction.ts b/lib/shared/src/chat/transcript/interaction.ts index b165ae9c6bb3..476b2bf48b03 100644 --- a/lib/shared/src/chat/transcript/interaction.ts +++ b/lib/shared/src/chat/transcript/interaction.ts @@ -1,4 +1,4 @@ -import type { ContextFile, ContextMessage, PreciseContext } from '../../codebase-context/messages' +import type { ContextItem, ContextMessage, PreciseContext } from '../../codebase-context/messages' import { isCodyIgnoredFile } from '../../cody-ignore/context-filter' import type { ChatMessage, InteractionMessage } from './messages' @@ -7,7 +7,7 @@ export interface InteractionJSON { humanMessage: InteractionMessage assistantMessage: InteractionMessage fullContext: ContextMessage[] - usedContextFiles: ContextFile[] + usedContextFiles: ContextItem[] usedPreciseContext: PreciseContext[] timestamp: string @@ -20,7 +20,7 @@ export class Interaction { private readonly humanMessage: InteractionMessage, private assistantMessage: InteractionMessage, private fullContext: Promise, - private usedContextFiles: ContextFile[], + private usedContextFiles: ContextItem[], private usedPreciseContext: PreciseContext[] = [], public readonly timestamp: string = new Date().toISOString() ) {} @@ -69,7 +69,7 @@ export class Interaction { return msgs.map(msg => ({ ...msg })) } - public setUsedContext(usedContextFiles: ContextFile[], usedPreciseContext: PreciseContext[]): void { + public setUsedContext(usedContextFiles: ContextItem[], usedPreciseContext: PreciseContext[]): void { this.usedContextFiles = usedContextFiles this.usedPreciseContext = usedPreciseContext } diff --git a/lib/shared/src/chat/transcript/messages.ts b/lib/shared/src/chat/transcript/messages.ts index 8e201c81951e..b11e1dcf3eb0 100644 --- a/lib/shared/src/chat/transcript/messages.ts +++ b/lib/shared/src/chat/transcript/messages.ts @@ -1,4 +1,4 @@ -import type { ContextFile, PreciseContext } from '../../codebase-context/messages' +import type { ContextItem, PreciseContext } from '../../codebase-context/messages' import type { Message } from '../../sourcegraph-api' import type { TranscriptJSON } from '.' @@ -13,7 +13,7 @@ export interface ChatButton { export interface ChatMessage extends Message { displayText?: string - contextFiles?: ContextFile[] + contextFiles?: ContextItem[] preciseContext?: PreciseContext[] buttons?: ChatButton[] data?: any @@ -62,7 +62,7 @@ export interface ChatHistory { export interface ChatInputHistory { inputText: string - inputContextFiles: ContextFile[] + inputContextFiles: ContextItem[] } export type ChatEventSource = diff --git a/lib/shared/src/codebase-context/index.ts b/lib/shared/src/codebase-context/index.ts index 677600910d59..4e3c378bfe5b 100644 --- a/lib/shared/src/codebase-context/index.ts +++ b/lib/shared/src/codebase-context/index.ts @@ -1,7 +1,6 @@ import type { URI } from 'vscode-uri' import { ProgrammingLanguage, languageFromFilename } from '../common/languages' import type { Configuration } from '../configuration' -import type { ActiveTextEditorSelectionRange } from '../editor' import type { IRemoteSearch, IndexedKeywordContextFetcher, @@ -10,9 +9,10 @@ import type { import { populateCodeContextTemplate, populateMarkdownContextTemplate } from '../prompt/templates' import type { EmbeddingsSearchResult } from '../sourcegraph-api/graphql/client' +import type { RangeData } from '../common/range' import { - type ContextFile, type ContextFileSource, + type ContextItem, type ContextMessage, getContextMessageWithResponse, } from './messages' @@ -103,7 +103,7 @@ export class CodebaseContext { } public static makeContextMessageWithResponse(groupedResults: { - file: ContextFile & Required> + file: ContextItem & Required> results: string[] }): ContextMessage[] { const contextTemplateFn = @@ -122,12 +122,12 @@ export class CodebaseContext { function groupResultsByFile( results: EmbeddingsSearchResult[] -): { file: ContextFile & Required>; results: string[] }[] { - const originalFileOrder: (ContextFile & Required>)[] = [] +): { file: ContextItem & Required>; results: string[] }[] { + const originalFileOrder: (ContextItem & Required>)[] = [] for (const result of results) { if ( !originalFileOrder.find( - (ogFile: ContextFile) => ogFile.uri.toString() === result.uri.toString() + (ogFile: ContextItem) => ogFile.uri.toString() === result.uri.toString() ) ) { originalFileOrder.push({ @@ -137,6 +137,7 @@ function groupResultsByFile( range: createContextFileRange(result), source: 'embeddings', type: 'file', + content: '', }) } } @@ -187,7 +188,7 @@ function contextMessageWithSource( return message } -function createContextFileRange(result: EmbeddingsSearchResult): ActiveTextEditorSelectionRange { +function createContextFileRange(result: EmbeddingsSearchResult): RangeData { return { start: { line: result.startLine, diff --git a/lib/shared/src/codebase-context/messages.ts b/lib/shared/src/codebase-context/messages.ts index eccd20cffc47..51563bfafe3d 100644 --- a/lib/shared/src/codebase-context/messages.ts +++ b/lib/shared/src/codebase-context/messages.ts @@ -1,6 +1,6 @@ import type { URI } from 'vscode-uri' -import type { ActiveTextEditorSelectionRange } from '../editor' +import type { RangeData } from '../common/range' import { displayPath } from '../editor/displayPath' import type { Message } from '../sourcegraph-api' @@ -28,9 +28,9 @@ export type ContextFileType = 'file' | 'symbol' export type SymbolKind = 'class' | 'function' | 'method' -interface ContextFileCommon { +interface ContextItemCommon { uri: URI - range?: ActiveTextEditorSelectionRange + range?: RangeData repoName?: string revision?: string @@ -43,9 +43,9 @@ interface ContextFileCommon { content?: string } -export type ContextFile = ContextFileFile | ContextFileSymbol -export type ContextFileFile = ContextFileCommon & { type: 'file' } -export type ContextFileSymbol = ContextFileCommon & { +export type ContextItem = ContextItemFile | ContextItemSymbol +export type ContextItemFile = ContextItemCommon & { type: 'file' } +export type ContextItemSymbol = ContextItemCommon & { type: 'symbol' /** The fuzzy name of the symbol (if this represents a symbol). */ @@ -55,7 +55,7 @@ export type ContextFileSymbol = ContextFileCommon & { } export interface ContextMessage extends Required { - file?: ContextFile + file?: ContextItem preciseContext?: PreciseContext } @@ -89,7 +89,7 @@ export interface HoverContext { export function getContextMessageWithResponse( text: string, - file: ContextFile, + file: ContextItem, response = 'Ok.', source: ContextFileSource = 'editor' ): ContextMessage[] { @@ -101,20 +101,24 @@ export function getContextMessageWithResponse( ] } -export function createContextMessageByFile(file: ContextFile, content: string): ContextMessage[] { - const code = content || file.content - if (!code) { +export function createContextMessageByFile(item: ContextItem, content: string): ContextMessage[] { + if (!content) { + content = item.content ?? '' + } + if (!content) { return [] } - const filepath = displayPath(file.uri) return [ { speaker: 'human', text: - file.type === 'file' - ? `Context from file path @${filepath}:\n${code}` - : `$${file.symbolName} is a ${file.kind} symbol from file path @${filepath}:\n${code}`, - file, + item.type === 'file' + ? `Context from file path ${displayPath(item.uri)}:\n${content}` + : `${item.symbolName} is a ${item.kind} symbol from file path ${displayPath( + item.uri + )}:\n${content}`, + + file: item, }, { speaker: 'assistant', text: 'OK.' }, ] diff --git a/lib/shared/src/common/range.ts b/lib/shared/src/common/range.ts new file mode 100644 index 000000000000..6c05aacd8b3e --- /dev/null +++ b/lib/shared/src/common/range.ts @@ -0,0 +1,24 @@ +/** + * A range of text in a document. Unlike {@link vscode.Range}, this just contains the data. Do not + * use {@link vscode.Range} when serializing to JSON because it serializes to an array `[start, + * end]`, which is impossible to deserialize correctly without knowing that the value is for a + * {@link vscode.Range}. + */ +export interface RangeData { + start: { line: number; character: number } + end: { line: number; character: number } +} + +/** + * Return the plain {@link RangeData} for a rich instance of the class {@link vscode.Range}. + */ +export function toRangeData(range: R): RangeData +export function toRangeData(range: R | undefined): RangeData | undefined +export function toRangeData(range: R | undefined): RangeData | undefined { + return range + ? { + start: { line: range.start.line, character: range.start.character }, + end: { line: range.end.line, character: range.end.character }, + } + : undefined +} diff --git a/lib/shared/src/editor/index.ts b/lib/shared/src/editor/index.ts index e89f43e47ce0..21ba223613f6 100644 --- a/lib/shared/src/editor/index.ts +++ b/lib/shared/src/editor/index.ts @@ -1,26 +1,16 @@ import type { URI } from 'vscode-uri' +import type { RangeData } from '../common/range' export interface ActiveTextEditor { content: string fileUri: URI repoName?: string revision?: string - selectionRange?: ActiveTextEditorSelectionRange + selectionRange?: RangeData ignored?: boolean } -export interface ActiveTextEditorSelectionRange { - start: { - line: number - character: number - } - end: { - line: number - character: number - } -} - export interface ActiveTextEditorSelection { fileUri: URI repoName?: string @@ -28,14 +18,14 @@ export interface ActiveTextEditorSelection { precedingText: string selectedText: string followingText: string - selectionRange?: ActiveTextEditorSelectionRange | null + selectionRange?: RangeData | null } export type ActiveTextEditorDiagnosticType = 'error' | 'warning' | 'information' | 'hint' export interface ActiveTextEditorDiagnostic { type: ActiveTextEditorDiagnosticType - range: ActiveTextEditorSelectionRange + range: RangeData text: string message: string } @@ -57,16 +47,11 @@ export interface Editor { /** * Get diagnostics (errors, warnings, hints) for a range within the active text editor. */ - getActiveTextEditorDiagnosticsForRange( - range: ActiveTextEditorSelectionRange - ): ActiveTextEditorDiagnostic[] | null + getActiveTextEditorDiagnosticsForRange(range: RangeData): ActiveTextEditorDiagnostic[] | null getActiveTextEditorVisibleContent(): ActiveTextEditorVisibleContent | null - getTextEditorContentForFile( - uri: URI, - range?: ActiveTextEditorSelectionRange - ): Promise + getTextEditorContentForFile(uri: URI, range?: RangeData): Promise showWarningMessage(message: string): Promise } @@ -92,10 +77,7 @@ export class NoopEditor implements Editor { return null } - public getTextEditorContentForFile( - _uri: URI, - _range?: ActiveTextEditorSelectionRange - ): Promise { + public getTextEditorContentForFile(_uri: URI, _range?: RangeData): Promise { return Promise.resolve(undefined) } diff --git a/lib/shared/src/index.ts b/lib/shared/src/index.ts index b8d2bd92aa34..4f48d3e4f4d8 100644 --- a/lib/shared/src/index.ts +++ b/lib/shared/src/index.ts @@ -49,10 +49,10 @@ export type { } from './codebase-context/context-status' export { createContextMessageByFile, getContextMessageWithResponse } from './codebase-context/messages' export type { - ContextFile, - ContextFileFile, + ContextItem, + ContextItemFile, ContextFileSource, - ContextFileSymbol, + ContextItemSymbol, ContextFileType, ContextMessage, HoverContext, @@ -62,6 +62,7 @@ export type { export type { CodyCommand, CodyCommandContext, CodyCommandType } from './commands/types' export { type DefaultCodyCommands, DefaultChatCommands } from './commands/types' export { dedupeWith, isDefined, isErrorLike, pluralize } from './common' +export { type RangeData, toRangeData } from './common/range' export { ProgrammingLanguage, languageFromFilename, @@ -93,7 +94,6 @@ export type { ActiveTextEditorDiagnostic, ActiveTextEditorDiagnosticType, ActiveTextEditorSelection, - ActiveTextEditorSelectionRange, ActiveTextEditorVisibleContent, Editor, } from './editor' diff --git a/lib/shared/src/local-context/index.ts b/lib/shared/src/local-context/index.ts index 530033acabd6..3dedd5693d99 100644 --- a/lib/shared/src/local-context/index.ts +++ b/lib/shared/src/local-context/index.ts @@ -1,9 +1,9 @@ import type { URI } from 'vscode-uri' -import type { ContextFile, ContextFileFile } from '../codebase-context/messages' +import type { ContextItem, ContextItemFile } from '../codebase-context/messages' import type { EmbeddingsSearchResult } from '../sourcegraph-api/graphql/client' -export type ContextResult = ContextFile & { +export type ContextResult = ContextItem & { repoName?: string revision?: string content: string @@ -20,7 +20,7 @@ export interface LocalEmbeddingsFetcher { // Minimal interface so inline edit can use remote search for context. export interface IRemoteSearch { setWorkspaceUri(uri: URI): Promise - search(query: string): Promise + search(query: string): Promise } interface Point { diff --git a/lib/shared/src/prompt/truncation.ts b/lib/shared/src/prompt/truncation.ts index faef2c0e1df9..820aed6d84a5 100644 --- a/lib/shared/src/prompt/truncation.ts +++ b/lib/shared/src/prompt/truncation.ts @@ -1,4 +1,4 @@ -import type { ActiveTextEditorSelectionRange } from '../editor' +import type { RangeData } from '../common/range' import { CHARS_PER_TOKEN } from './constants' @@ -20,7 +20,7 @@ export function truncateText(text: string, maxTokens: number): string { export function truncateTextNearestLine( text: string, maxBytes: number -): { truncated: string; range?: ActiveTextEditorSelectionRange } { +): { truncated: string; range?: RangeData } { if (text.length <= maxBytes) { return { truncated: text } } diff --git a/lib/shared/src/test/mocks.ts b/lib/shared/src/test/mocks.ts index 69e416c39203..473b55346395 100644 --- a/lib/shared/src/test/mocks.ts +++ b/lib/shared/src/test/mocks.ts @@ -1,10 +1,10 @@ import type { URI } from 'vscode-uri' +import type { RangeData } from '../common/range' import type { ActiveTextEditor, ActiveTextEditorDiagnostic, ActiveTextEditorSelection, - ActiveTextEditorSelectionRange, ActiveTextEditorVisibleContent, Editor, } from '../editor' @@ -38,7 +38,7 @@ export class MockEditor implements Editor { } public getActiveTextEditorDiagnosticsForRange( - range: ActiveTextEditorSelectionRange + range: RangeData ): ActiveTextEditorDiagnostic[] | null { return this.mocks.getActiveTextEditorDiagnosticsForRange?.(range) ?? null } @@ -55,10 +55,7 @@ export class MockEditor implements Editor { return this.mocks.showWarningMessage?.(message) ?? Promise.resolve() } - public async getTextEditorContentForFile( - uri: URI, - range?: ActiveTextEditorSelectionRange - ): Promise { + public async getTextEditorContentForFile(uri: URI, range?: RangeData): Promise { return this.mocks.getTextEditorContentForFile?.(uri, range) ?? Promise.resolve(undefined) } } diff --git a/lib/ui/src/Chat.tsx b/lib/ui/src/Chat.tsx index 4529a126139b..a246c45a9561 100644 --- a/lib/ui/src/Chat.tsx +++ b/lib/ui/src/Chat.tsx @@ -8,7 +8,7 @@ import { type ChatInputHistory, type ChatMessage, type CodyCommand, - type ContextFile, + type ContextItem, type Guardrails, type ModelProvider, getAtMentionQuery, @@ -40,7 +40,7 @@ interface ChatProps extends ChatClassNames { onSubmit: ( text: string, submitType: WebviewChatSubmitType, - userContextFiles?: Map + userContextFiles?: Map ) => void gettingStartedComponent?: React.FunctionComponent gettingStartedComponentProps?: any @@ -73,8 +73,8 @@ interface ChatProps extends ChatClassNames { input: string ) => [string, CodyCommand][] isTranscriptError?: boolean - contextSelection?: ContextFile[] | null - setContextSelection: (context: ContextFile[] | null) => void + contextSelection?: ContextItem[] | null + setContextSelection: (context: ContextItem[] | null) => void UserContextSelectorComponent?: React.FunctionComponent chatModels?: ModelProvider[] EnhancedContextSettings?: React.FunctionComponent<{ @@ -157,8 +157,8 @@ export interface CodeBlockActionsProps { } export interface UserContextSelectorProps { - onSelected: (context: ContextFile, queryEndsWithColon?: boolean) => void - contextSelection?: ContextFile[] + onSelected: (context: ContextItem, queryEndsWithColon?: boolean) => void + contextSelection?: ContextItem[] selected?: number onSubmit: (input: string, inputType: 'user') => void setSelectedChatContext: (arg: number) => void @@ -243,7 +243,7 @@ export const Chat: React.FunctionComponent = ({ const [historyIndex, setHistoryIndex] = useState(inputHistory.length) // The context files added via the chat input by user - const [chatContextFiles, setChatContextFiles] = useState>(new Map([])) + const [chatContextFiles, setChatContextFiles] = useState>(new Map([])) const [selectedChatContext, setSelectedChatContext] = useState(0) const [currentChatContextQuery, setCurrentChatContextQuery] = useState(undefined) @@ -327,8 +327,8 @@ export const Chat: React.FunctionComponent = ({ ) // Add old context files from the transcript to the map - const useOldChatMessageContext = (oldContextFiles: ContextFile[]) => { - const contextFilesMap = new Map(chatContextFiles) + const useOldChatMessageContext = (oldContextFiles: ContextItem[]) => { + const contextFilesMap = new Map(chatContextFiles) for (const file of oldContextFiles) { const fileDisplayText = getContextFileDisplayText(file) contextFilesMap.set(fileDisplayText, file) @@ -343,7 +343,7 @@ export const Chat: React.FunctionComponent = ({ * Allows users to quickly insert file context into the chat input. */ const onChatContextSelected = useCallback( - (selected: ContextFile, queryEndsWithColon = false): void => { + (selected: ContextItem, queryEndsWithColon = false): void => { const atRangeEndingRegex = /:\d+(-\d+)?$/ const inputBeforeCaret = formInput.slice(0, inputCaretPosition) diff --git a/lib/ui/src/chat/components/EnhancedContext.tsx b/lib/ui/src/chat/components/EnhancedContext.tsx index fa918a87e5dd..0b31018f6e35 100644 --- a/lib/ui/src/chat/components/EnhancedContext.tsx +++ b/lib/ui/src/chat/components/EnhancedContext.tsx @@ -2,7 +2,7 @@ import React from 'react' import type { URI } from 'vscode-uri' -import type { ActiveTextEditorSelectionRange, ContextFile } from '@sourcegraph/cody-shared' +import type { ContextItem, RangeData } from '@sourcegraph/cody-shared' import { TranscriptAction } from '../actions/TranscriptAction' @@ -17,12 +17,12 @@ export interface FileLinkProps { repoName?: string revision?: string source?: string - range?: ActiveTextEditorSelectionRange + range?: RangeData title?: string } export const EnhancedContext: React.FunctionComponent<{ - contextFiles: ContextFile[] + contextFiles: ContextItem[] fileLinkComponent: React.FunctionComponent className?: string }> = React.memo(function ContextFilesContent({ contextFiles, fileLinkComponent: FileLink, className }) { diff --git a/vscode/src/chat/chat-view/SimpleChatModel.ts b/vscode/src/chat/chat-view/SimpleChatModel.ts index 1499626c05e0..78ae762f1fae 100644 --- a/vscode/src/chat/chat-view/SimpleChatModel.ts +++ b/vscode/src/chat/chat-view/SimpleChatModel.ts @@ -3,6 +3,7 @@ import { findLast } from 'lodash' import { type ChatError, type ChatMessage, + type ContextItem, type InteractionJSON, type InteractionMessage, type Message, @@ -10,11 +11,11 @@ import { errorToChatError, isCodyIgnoredFile, reformatBotMessageForChat, + toRangeData, } from '@sourcegraph/cody-shared' import type { Repo } from '../../context/repo-fetcher' -import type { ContextItem } from '../../prompt-builder/types' -import { contextItemsToContextFiles, getChatPanelTitle } from './chat-helpers' +import { getChatPanelTitle } from './chat-helpers' /** * Interface for a chat message with additional context. @@ -210,7 +211,7 @@ function messageToInteractionJSON( botMessage?.message?.speaker === 'assistant' ? messageToInteractionMessage(botMessage) : { speaker: 'assistant' }, - usedContextFiles: contextItemsToContextFiles(humanMessage.newContextUsed ?? []), + usedContextFiles: humanMessage.newContextUsed ?? [], // These fields are unused on deserialization fullContext: [], usedPreciseContext: [], @@ -232,7 +233,11 @@ export function toViewMessage(mwc: MessageWithContext): ChatMessage { ...mwc.message, error: mwc.error, displayText, - contextFiles: contextItemsToContextFiles(mwc.newContextUsed || []), + contextFiles: (mwc.newContextUsed ?? []).map(item => ({ + ...item, + // De-hydrate because vscode.Range serializes to `[start, end]` in JSON. + range: toRangeData(item.range), + })), } } diff --git a/vscode/src/chat/chat-view/SimpleChatPanelProvider.test.ts b/vscode/src/chat/chat-view/SimpleChatPanelProvider.test.ts index 7ebc35b42fa0..49b984ed9ea1 100644 --- a/vscode/src/chat/chat-view/SimpleChatPanelProvider.test.ts +++ b/vscode/src/chat/chat-view/SimpleChatPanelProvider.test.ts @@ -1,11 +1,10 @@ import { describe, expect, test } from 'vitest' import { URI } from 'vscode-uri' -import type { Editor } from '@sourcegraph/cody-shared' +import type { ContextItem, Editor } from '@sourcegraph/cody-shared' import '../../testutils/vscode' -import type { ContextItem } from '../../prompt-builder/types' import { contextFilesToContextItems } from './SimpleChatPanelProvider' describe('contextFilesToContextItems', () => { @@ -33,6 +32,8 @@ describe('contextFilesToContextItems', () => { ], true ) - expect(contextItems).toEqual([{ uri: URI.parse('file:///a.txt'), text: 'a' }]) + expect(contextItems).toEqual([ + { type: 'file', uri: URI.parse('file:///a.txt'), content: 'a' }, + ]) }) }) diff --git a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts index 8aefb7cee5ec..c2df94512ef9 100644 --- a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts +++ b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts @@ -7,7 +7,7 @@ import { type ChatInputHistory, type ChatMessage, ConfigFeaturesSingleton, - type ContextFile, + type ContextItem, type ContextMessage, type Editor, FeatureFlag, @@ -65,7 +65,6 @@ import type { RemoteRepoPicker } from '../../context/repo-picker' import type { ContextRankingController } from '../../local-context/context-ranking' import { chatModel } from '../../models' import { getContextWindowForModel } from '../../models/utilts' -import type { ContextItem } from '../../prompt-builder/types' import { recordExposedExperimentsToSpan } from '../../services/open-telemetry/utils' import type { MessageErrorType } from '../MessageProvider' import type { @@ -394,7 +393,7 @@ export class SimpleChatPanelProvider implements vscode.Disposable, ChatSession { requestID: string, inputText: string, submitType: ChatSubmitType, - userContextFiles: ContextFile[], + userContextFiles: ContextItem[], addEnhancedContext: boolean, source?: ChatEventSource ): Promise { @@ -541,7 +540,7 @@ export class SimpleChatPanelProvider implements vscode.Disposable, ChatSession { requestID: string, text: string, index?: number, - contextFiles: ContextFile[] = [], + contextFiles: ContextItem[] = [], addEnhancedContext = true ): Promise { telemetryService.log('CodyVSCodeExtension:editChatButton:clicked', undefined, { @@ -1275,37 +1274,32 @@ async function newChatModelfromTranscriptJSON( export async function contextFilesToContextItems( editor: Editor, - files: ContextFile[], + items: ContextItem[], fetchContent?: boolean ): Promise { return ( await Promise.all( - files.map(async (file: ContextFile): Promise => { - const range = viewRangeToRange(file.range) - let text = file.content - if (!text && fetchContent) { + items.map(async (item: ContextItem): Promise => { + const range = viewRangeToRange(item.range) + let content = item.content + if (!item.content && fetchContent) { try { - text = await editor.getTextEditorContentForFile(file.uri, range) + content = await editor.getTextEditorContentForFile(item.uri, range) } catch (error) { void vscode.window.showErrorMessage( - `Cody could not include context from ${file.uri}. (Reason: ${error})` + `Cody could not include context from ${item.uri}. (Reason: ${error})` ) return null } } - return { - uri: file.uri, - range, - text: text || '', - source: file.source, - } + return { ...item, content: content! } }) ) ).filter(isDefined) } function deserializedContextFilesToContextItems( - files: ContextFile[], + files: ContextItem[], contextMessages: ContextMessage[] ): ContextItem[] { const contextByFile = new Map() @@ -1316,7 +1310,7 @@ function deserializedContextFilesToContextItems( contextByFile.set(contextMessage.file.uri.toString(), contextMessage) } - return files.map((file: ContextFile): ContextItem => { + return files.map((file: ContextItem): ContextItem => { const range = viewRangeToRange(file.range) let text = file.content if (!text) { @@ -1326,9 +1320,10 @@ function deserializedContextFilesToContextItems( } } return { + type: 'file', uri: file.uri, range, - text: text || '', + content: text || '', source: file.source, repoName: file.repoName, revision: file.revision, diff --git a/vscode/src/chat/chat-view/agentContextSorting.ts b/vscode/src/chat/chat-view/agentContextSorting.ts index 2ab9e8d2678d..c252fc313a57 100644 --- a/vscode/src/chat/chat-view/agentContextSorting.ts +++ b/vscode/src/chat/chat-view/agentContextSorting.ts @@ -1,5 +1,4 @@ -import type { ContextFile } from '@sourcegraph/cody-shared' -import type { ContextItem } from '../../prompt-builder/types' +import type { ContextItem } from '@sourcegraph/cody-shared' const isAgentTesting = process.env.CODY_SHIM_TESTING === 'true' @@ -22,11 +21,11 @@ export function sortContextItems(files: ContextItem[]): void { if (bySource !== 0) { return bySource } - return a.text.localeCompare(b.text) + return (a.content ?? '').localeCompare(b.content ?? '') }) } -export function sortContextFiles(files: ContextFile[]): void { +export function sortContextFiles(files: ContextItem[]): void { if (!isAgentTesting) { return } diff --git a/vscode/src/chat/chat-view/chat-helpers.test.ts b/vscode/src/chat/chat-view/chat-helpers.test.ts index 3b4c78c48b7b..5fda5dc1f835 100644 --- a/vscode/src/chat/chat-view/chat-helpers.test.ts +++ b/vscode/src/chat/chat-view/chat-helpers.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from 'vitest' import { CodebaseContext, - type ContextFile, + type ContextItem, populateCurrentEditorSelectedContextTemplate, populateCurrentSelectedCodeContextTemplate, testFileUri, @@ -10,13 +10,7 @@ import { import * as vscode from '../../testutils/mocks' -import type { ContextItem } from '../../prompt-builder/types' -import { - contextItemsToContextFiles, - contextMessageToContextItem, - getChatPanelTitle, - stripContextWrapper, -} from './chat-helpers' +import { contextMessageToContextItem, getChatPanelTitle, stripContextWrapper } from './chat-helpers' describe('unwrap context snippets', () => { test('should wrap and unwrap context item snippets', () => { @@ -27,26 +21,28 @@ describe('unwrap context snippets', () => { const testCases: TestCase[] = [ { contextItem: { + type: 'file', uri: testFileUri('test.ts'), range: new vscode.Range(0, 1, 2, 3), source: 'editor', - text: '// This is code context', + content: '// This is code context', }, }, { contextItem: { + type: 'file', uri: testFileUri('doc.md'), range: new vscode.Range(0, 1, 2, 3), source: 'editor', - text: 'This is markdown context', + content: 'This is markdown context', }, }, ] for (const testCase of testCases) { - const contextFiles = contextItemsToContextFiles([testCase.contextItem]) + const contextFiles = [testCase.contextItem] const contextMessages = CodebaseContext.makeContextMessageWithResponse({ - file: contextFiles[0] as ContextFile & Required>, + file: contextFiles[0] as ContextItem & Required>, results: [contextFiles[0].content || ''], }) const contextItem = contextMessageToContextItem(contextMessages[0]) diff --git a/vscode/src/chat/chat-view/chat-helpers.ts b/vscode/src/chat/chat-view/chat-helpers.ts index 02ccdaf266a2..3c9a846526aa 100644 --- a/vscode/src/chat/chat-view/chat-helpers.ts +++ b/vscode/src/chat/chat-view/chat-helpers.ts @@ -1,15 +1,10 @@ import * as vscode from 'vscode' -import type { - ActiveTextEditorSelectionRange, - ContextFile, - ContextMessage, -} from '@sourcegraph/cody-shared' -import type { ContextItem } from '../../prompt-builder/types' +import type { ContextItem, ContextMessage, RangeData } from '@sourcegraph/cody-shared' export async function openFile( uri: vscode.Uri, - range?: ActiveTextEditorSelectionRange, + range?: RangeData, currentViewColumn?: vscode.ViewColumn ): Promise { let viewColumn = vscode.ViewColumn.Beside @@ -41,7 +36,8 @@ export function contextMessageToContextItem(contextMessage: ContextMessage): Con } const range = contextMessage.file.range return { - text: contextText, + type: 'file', + content: contextText, uri: contextMessage.file.uri, source: contextMessage.file.source, range: @@ -88,41 +84,6 @@ export function stripContextWrapper(text: string): string | undefined { return undefined } -export function contextItemsToContextFiles(items: ContextItem[]): ContextFile[] { - const contextFiles: ContextFile[] = [] - for (const item of items) { - contextFiles.push({ - type: 'file', // TODO(sqs): some of these are symbols; preserve that `type` - uri: item.uri, - source: item.source || 'embeddings', - range: rangeToActiveTextEditorSelectionRange(item.range), - content: item.text, - repoName: item.repoName, - revision: item.revision, - title: item.title, - }) - } - return contextFiles -} - -function rangeToActiveTextEditorSelectionRange( - range?: vscode.Range -): ActiveTextEditorSelectionRange | undefined { - if (!range) { - return undefined - } - return { - start: { - line: range.start.line, - character: range.start.character, - }, - end: { - line: range.end.line, - character: range.end.character, - }, - } -} - export function getChatPanelTitle(lastDisplayText?: string, truncateTitle = true): string { if (!lastDisplayText) { return 'New Chat' @@ -137,7 +98,7 @@ export function getChatPanelTitle(lastDisplayText?: string, truncateTitle = true return lastDisplayText.length > 25 ? `${lastDisplayText.slice(0, 25).trim()}...` : lastDisplayText } -export function viewRangeToRange(range?: ActiveTextEditorSelectionRange): vscode.Range | undefined { +export function viewRangeToRange(range?: RangeData): vscode.Range | undefined { if (!range) { return undefined } diff --git a/vscode/src/chat/chat-view/context.test.ts b/vscode/src/chat/chat-view/context.test.ts index f211bd371bc8..0efc07573829 100644 --- a/vscode/src/chat/chat-view/context.test.ts +++ b/vscode/src/chat/chat-view/context.test.ts @@ -1,30 +1,29 @@ -import { testFileUri } from '@sourcegraph/cody-shared' +import { type ContextItem, testFileUri } from '@sourcegraph/cody-shared' import { describe, expect, it } from 'vitest' -import type { ContextItem } from '../../prompt-builder/types' import { fuseContext } from './context' describe('fuseContext', () => { const uri = testFileUri('test.ts') - const keywordItems = [ - { text: '0', uri }, - { text: '1', uri }, - { text: '2', uri }, - { text: '3', uri }, - { text: '4', uri }, - { text: '5', uri }, - { text: '6', uri }, - { text: '7', uri }, - { text: '8', uri }, - { text: '9', uri }, + const keywordItems: ContextItem[] = [ + { type: 'file', content: '0', uri, source: 'keyword' }, + { type: 'file', content: '1', uri, source: 'keyword' }, + { type: 'file', content: '2', uri, source: 'keyword' }, + { type: 'file', content: '3', uri, source: 'keyword' }, + { type: 'file', content: '4', uri, source: 'keyword' }, + { type: 'file', content: '5', uri, source: 'keyword' }, + { type: 'file', content: '6', uri, source: 'keyword' }, + { type: 'file', content: '7', uri, source: 'keyword' }, + { type: 'file', content: '8', uri, source: 'keyword' }, + { type: 'file', content: '9', uri, source: 'keyword' }, ] - const embeddingsItems = [ - { text: 'A', uri }, - { text: 'B', uri }, - { text: 'C', uri }, + const embeddingsItems: ContextItem[] = [ + { type: 'file', content: 'A', uri, source: 'embeddings' }, + { type: 'file', content: 'B', uri, source: 'embeddings' }, + { type: 'file', content: 'C', uri, source: 'embeddings' }, ] function joined(items: ContextItem[]): string { - return items.map(r => r.text).join('') + return items.map(r => r.content).join('') } it('includes the right 80-20 split', () => { @@ -34,24 +33,24 @@ describe('fuseContext', () => { }) it('skips over large items in an attempt to optimize utilization', () => { - const keywordItems = [ - { text: '0', uri }, - { text: '1', uri }, - { text: '2', uri }, - { text: '3', uri }, - { text: '4', uri }, - { text: '5', uri }, - { text: 'very large keyword item', uri }, - { text: '6', uri }, - { text: '7', uri }, - { text: '8', uri }, - { text: '9', uri }, + const keywordItems: ContextItem[] = [ + { type: 'file', content: '0', uri, source: 'keyword' }, + { type: 'file', content: '1', uri, source: 'keyword' }, + { type: 'file', content: '2', uri, source: 'keyword' }, + { type: 'file', content: '3', uri, source: 'keyword' }, + { type: 'file', content: '4', uri, source: 'keyword' }, + { type: 'file', content: '5', uri, source: 'keyword' }, + { type: 'file', content: 'very large keyword item', uri, source: 'keyword' }, + { type: 'file', content: '6', uri, source: 'keyword' }, + { type: 'file', content: '7', uri, source: 'keyword' }, + { type: 'file', content: '8', uri, source: 'keyword' }, + { type: 'file', content: '9', uri, source: 'keyword' }, ] - const embeddingsItems = [ - { text: 'A', uri }, - { text: 'very large embeddings item', uri }, - { text: 'B', uri }, - { text: 'C', uri }, + const embeddingsItems: ContextItem[] = [ + { type: 'file', content: 'A', uri, source: 'embeddings' }, + { type: 'file', content: 'very large embeddings item', uri, source: 'embeddings' }, + { type: 'file', content: 'B', uri, source: 'embeddings' }, + { type: 'file', content: 'C', uri, source: 'embeddings' }, ] const maxChars = 10 const result = fuseContext(keywordItems, embeddingsItems, maxChars) diff --git a/vscode/src/chat/chat-view/context.ts b/vscode/src/chat/chat-view/context.ts index 639ad06a945a..4eed5fee1311 100644 --- a/vscode/src/chat/chat-view/context.ts +++ b/vscode/src/chat/chat-view/context.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode' import { type ConfigurationUseContext, + type ContextItem, MAX_BYTES_PER_FILE, NUM_CODE_RESULTS, NUM_TEXT_RESULTS, @@ -18,7 +19,6 @@ import type { ContextRankingController } from '../../local-context/context-ranki import type { LocalEmbeddingsController } from '../../local-context/local-embeddings' import type { SymfRunner } from '../../local-context/symf' import { logDebug, logError } from '../../log' -import type { ContextItem } from '../../prompt-builder/types' import { viewRangeToRange } from './chat-helpers' interface GetEnhancedContextOptions { @@ -233,7 +233,8 @@ async function searchRemote( } return (await remoteSearch.query(userText)).map(result => { return { - text: result.content, + type: 'file', + content: result.content, range: new vscode.Range(result.startLine, 0, result.endLine, 0), uri: result.uri, source: 'unified', @@ -299,10 +300,11 @@ async function searchSymf( return [] } return { + type: 'file', uri: result.file, range, source: 'search', - text, + content: text, } } ) @@ -336,9 +338,10 @@ async function searchEmbeddingsLocal( ) contextItems.push({ + type: 'file', uri: result.uri, range, - text: result.content, + content: result.content, source: 'embeddings', }) } @@ -370,7 +373,8 @@ function getCurrentSelectionContext(editor: VSCodeEditor): ContextItem[] { return [ { - text: selection.selectedText, + type: 'file', + content: selection.selectedText, uri: selection.fileUri, range, source: 'selection', @@ -390,6 +394,7 @@ function getVisibleEditorContext(editor: VSCodeEditor): ContextItem[] { } return [ { + type: 'file', text: visible.content, uri: fileUri, source: 'editor', @@ -511,8 +516,9 @@ async function getReadmeContext(): Promise { return [ { + type: 'file', uri: readmeUri, - text: truncatedReadmeText, + content: truncatedReadmeText, range: viewRangeToRange(range), source: 'editor', }, @@ -555,7 +561,7 @@ export function fuseContext( const maxKeywordChars = embeddingsItems.length > 0 ? maxChars * 0.8 : maxChars for (const item of keywordItems) { - const len = item.text.length + const len = item.content?.length ?? 0 if (charsUsed + len <= maxKeywordChars) { charsUsed += len @@ -564,7 +570,7 @@ export function fuseContext( } for (const item of embeddingsItems) { - const len = item.text.length + const len = item.content?.length ?? 0 if (charsUsed + len <= maxChars) { charsUsed += len diff --git a/vscode/src/chat/chat-view/prompt.test.ts b/vscode/src/chat/chat-view/prompt.test.ts index f785e58bacac..e06b448625c5 100644 --- a/vscode/src/chat/chat-view/prompt.test.ts +++ b/vscode/src/chat/chat-view/prompt.test.ts @@ -1,3 +1,4 @@ +import type { ContextItem } from '@sourcegraph/cody-shared' import { afterEach, describe, expect, it, vi } from 'vitest' import * as vscode from 'vscode' import { PromptBuilder } from '../../prompt-builder' @@ -74,10 +75,11 @@ describe('DefaultPrompter', () => { it('tryAddContext limit should not allow prompt to exceed overall limit', async () => { const overallLimit = 1 const promptBuilder = new PromptBuilder(overallLimit) - const contextItems = [ + const contextItems: ContextItem[] = [ { + type: 'file', uri: vscode.Uri.file('/foo/bar'), - text: 'foobar', + content: 'foobar', }, ] diff --git a/vscode/src/chat/chat-view/prompt.ts b/vscode/src/chat/chat-view/prompt.ts index acf07e71414e..d277fd72f2d9 100644 --- a/vscode/src/chat/chat-view/prompt.ts +++ b/vscode/src/chat/chat-view/prompt.ts @@ -1,11 +1,15 @@ import * as vscode from 'vscode' -import { type Message, getSimplePreamble, wrapInActiveSpan } from '@sourcegraph/cody-shared' +import { + type ContextItem, + type Message, + getSimplePreamble, + wrapInActiveSpan, +} from '@sourcegraph/cody-shared' import { logDebug } from '../../log' import { PromptBuilder } from '../../prompt-builder' -import type { ContextItem } from '../../prompt-builder/types' import type { MessageWithContext, SimpleChatModel } from './SimpleChatModel' import { sortContextItems } from './agentContextSorting' diff --git a/vscode/src/chat/protocol.ts b/vscode/src/chat/protocol.ts index ba67d5844087..e62843c34dcb 100644 --- a/vscode/src/chat/protocol.ts +++ b/vscode/src/chat/protocol.ts @@ -1,13 +1,13 @@ import type { URI } from 'vscode-uri' import type { - ActiveTextEditorSelectionRange, ChatMessage, CodyLLMSiteConfiguration, ConfigurationWithAccessToken, - ContextFile, + ContextItem, EnhancedContextContextT, ModelProvider, + RangeData, SearchPanelFile, TelemetryEventProperties, UserLocalHistory, @@ -42,14 +42,14 @@ export type WebviewMessage = | { command: 'openFile' uri: URI - range?: ActiveTextEditorSelectionRange + range?: RangeData } | { command: 'openLocalFileWithRange' filePath: string // Note: we're not using vscode.Range objects or nesting here, as the protocol // tends to munge the type in a weird way (nested fields become array indices). - range?: ActiveTextEditorSelectionRange + range?: RangeData } | ({ command: 'edit' } & WebviewEditMessage) | { command: 'context/get-remote-search-repos' } @@ -89,7 +89,7 @@ export type WebviewMessage = | { command: 'show-search-result' uri: URI - range: ActiveTextEditorSelectionRange + range: RangeData } | { command: 'reset' @@ -121,7 +121,7 @@ export type ExtensionMessage = | { type: 'transcript-errors'; isTranscriptError: boolean } | { type: 'userContextFiles' - userContextFiles: ContextFile[] | null + userContextFiles: ContextItem[] | null } | { type: 'chatModels'; models: ModelProvider[] } | { @@ -166,7 +166,7 @@ interface WebviewEditMessage extends WebviewContextMessage { interface WebviewContextMessage { addEnhancedContext?: boolean - contextFiles?: ContextFile[] + contextFiles?: ContextItem[] } export interface ExtensionTranscriptMessage { diff --git a/vscode/src/commands/context/current-file.ts b/vscode/src/commands/context/current-file.ts index 2224ba30756c..c1e509af4ad6 100644 --- a/vscode/src/commands/context/current-file.ts +++ b/vscode/src/commands/context/current-file.ts @@ -1,5 +1,5 @@ import { - type ContextFile, + type ContextItem, MAX_CURRENT_FILE_TOKENS, logError, truncateText, @@ -8,7 +8,7 @@ import { import * as vscode from 'vscode' import { getEditor } from '../../editor/active-editor' -export async function getContextFileFromCurrentFile(): Promise { +export async function getContextFileFromCurrentFile(): Promise { return wrapInActiveSpan('commands.context.file', async span => { try { const editor = getEditor() @@ -37,7 +37,7 @@ export async function getContextFileFromCurrentFile(): Promise { content: truncateText(content, MAX_CURRENT_FILE_TOKENS), source: 'editor', range: selection, - } as ContextFile, + } as ContextItem, ] } catch (error) { logError('getContextFileFromCurrentFile', 'failed', { verbose: error }) diff --git a/vscode/src/commands/context/directory.ts b/vscode/src/commands/context/directory.ts index b80d2101356f..e167c6b2ffab 100644 --- a/vscode/src/commands/context/directory.ts +++ b/vscode/src/commands/context/directory.ts @@ -1,5 +1,5 @@ import { - type ContextFile, + type ContextItem, MAX_CURRENT_FILE_TOKENS, logError, truncateText, @@ -17,9 +17,9 @@ import { getEditor } from '../../editor/active-editor' * truncates it, and adds it to the context messages along with the file name. * Limits file sizes to 1MB. */ -export async function getContextFileFromDirectory(directory?: URI): Promise { +export async function getContextFileFromDirectory(directory?: URI): Promise { return wrapInActiveSpan('commands.context.directory', async () => { - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] const editor = getEditor() const document = editor?.active?.document @@ -65,7 +65,7 @@ export async function getContextFileFromDirectory(directory?: URI): Promise { +export async function getContextFileFromUri(file: URI): Promise { return wrapInActiveSpan('commands.context.filePath', async span => { try { const doc = await vscode.workspace.openTextDocument(file) diff --git a/vscode/src/commands/context/index.ts b/vscode/src/commands/context/index.ts index 88ad62910c8b..262087afe0ab 100644 --- a/vscode/src/commands/context/index.ts +++ b/vscode/src/commands/context/index.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' -import { type CodyCommandContext, type ContextFile, isCodyIgnoredFile } from '@sourcegraph/cody-shared' +import { type CodyCommandContext, type ContextItem, isCodyIgnoredFile } from '@sourcegraph/cody-shared' import { Utils } from 'vscode-uri' import { logDebug } from '../../log' @@ -20,9 +20,9 @@ import { getContextFileFromCursor } from './selection' * * The returned context files are filtered to remove any files ignored by Cody. */ -export const getCommandContextFiles = async (config: CodyCommandContext): Promise => { +export const getCommandContextFiles = async (config: CodyCommandContext): Promise => { try { - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] const workspaceRoot = vscode.workspace.workspaceFolders?.[0].uri // Return immediately if context.none is true diff --git a/vscode/src/commands/context/open-tabs.ts b/vscode/src/commands/context/open-tabs.ts index 07c2bc339110..3f0c639550a9 100644 --- a/vscode/src/commands/context/open-tabs.ts +++ b/vscode/src/commands/context/open-tabs.ts @@ -1,4 +1,4 @@ -import { type ContextFile, logError, wrapInActiveSpan } from '@sourcegraph/cody-shared' +import { type ContextItem, logError, wrapInActiveSpan } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { getContextFileFromUri } from './file-path' @@ -8,9 +8,9 @@ import { getContextFileFromUri } from './file-path' * Iterates through all open tabs, filters to only file tabs in the workspace, * and then creates ContextFile objects for each valid tab. */ -export async function getContextFileFromTabs(): Promise { +export async function getContextFileFromTabs(): Promise { return wrapInActiveSpan('commands.context.openTabs', async span => { - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] try { // Get open tabs from the current editor const tabGroups = vscode.window.tabGroups.all diff --git a/vscode/src/commands/context/selection.ts b/vscode/src/commands/context/selection.ts index 6a5e43986ce0..fbef634c6e28 100644 --- a/vscode/src/commands/context/selection.ts +++ b/vscode/src/commands/context/selection.ts @@ -1,5 +1,5 @@ import { - type ContextFile, + type ContextItem, MAX_CURRENT_FILE_TOKENS, logError, truncateText, @@ -14,7 +14,7 @@ import { getSmartSelection } from '../../editor/utils' * When no selection is made, try getting the smart selection based on the cursor position. * If no smart selection is found, use the visible range of the editor instead. */ -export async function getContextFileFromCursor(): Promise { +export async function getContextFileFromCursor(): Promise { return wrapInActiveSpan('commands.context.selection', async span => { try { const editor = getEditor() @@ -42,7 +42,7 @@ export async function getContextFileFromCursor(): Promise { content: truncateText(content, MAX_CURRENT_FILE_TOKENS), source: 'selection', range: selection, - } as ContextFile, + } as ContextItem, ] } catch (error) { logError('getContextFileFromCursor', 'failed', { verbose: error }) diff --git a/vscode/src/commands/context/shell.ts b/vscode/src/commands/context/shell.ts index b5269f783da8..1a7f3a9c8c9b 100644 --- a/vscode/src/commands/context/shell.ts +++ b/vscode/src/commands/context/shell.ts @@ -8,7 +8,7 @@ import { logError } from '../../log' import path from 'node:path/posix' import { - type ContextFile, + type ContextItem, MAX_CURRENT_FILE_TOKENS, truncateText, wrapInActiveSpan, @@ -22,7 +22,7 @@ const _exec = promisify(exec) * Executes the given shell command, captures the output, wraps it in a context format, * and returns it as a ContextFile. */ -export async function getContextFileFromShell(command: string): Promise { +export async function getContextFileFromShell(command: string): Promise { return wrapInActiveSpan('commands.context.command', async span => { const rootDir = os.homedir() || process.env.HOME || process.env.USERPROFILE || '' @@ -55,7 +55,7 @@ export async function getContextFileFromShell(command: string): Promise { +export async function getContextFilesForAddingUnitTestCases(testFile: URI): Promise { return wrapInActiveSpan('commands.context.testCase', async span => { // Get the context from the current directory // and then find the original file of the test file in the returned context @@ -19,7 +19,7 @@ export async function getContextFilesForAddingUnitTestCases(testFile: URI): Prom } // TODO (bee) improves context search - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] // exclude any files in the path with e2e, integration, node_modules, or dist const excludePattern = '**/*{e2e,integration,node_modules,dist}*/**' // To search for files in the current directory only diff --git a/vscode/src/commands/context/unit-test-chat.ts b/vscode/src/commands/context/unit-test-chat.ts index 383e0efaff19..3d59395aa1f6 100644 --- a/vscode/src/commands/context/unit-test-chat.ts +++ b/vscode/src/commands/context/unit-test-chat.ts @@ -1,4 +1,4 @@ -import { type ContextFile, wrapInActiveSpan } from '@sourcegraph/cody-shared' +import { type ContextItem, wrapInActiveSpan } from '@sourcegraph/cody-shared' import type * as vscode from 'vscode' @@ -18,9 +18,9 @@ import { getWorkspaceFilesContext } from './workspace' * NOTE: This is used by the current unit test commands to get context files. * NOTE: Will be replaced by the new unit test commands once it's ready. */ -export async function getContextFilesForTestCommand(file: vscode.Uri): Promise { +export async function getContextFilesForTestCommand(file: vscode.Uri): Promise { return wrapInActiveSpan('commands.context.testChat', async span => { - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] // exclude any files in the path with e2e, integration, node_modules, or dist const excludePattern = '**/*{e2e,integration,node_modules,dist}*/**' diff --git a/vscode/src/commands/context/unit-test-file.ts b/vscode/src/commands/context/unit-test-file.ts index 7528e5079fd9..268d35cd9003 100644 --- a/vscode/src/commands/context/unit-test-file.ts +++ b/vscode/src/commands/context/unit-test-file.ts @@ -1,4 +1,4 @@ -import { type ContextFile, wrapInActiveSpan } from '@sourcegraph/cody-shared' +import { type ContextItem, wrapInActiveSpan } from '@sourcegraph/cody-shared' import type { URI } from 'vscode-uri' import { getSearchPatternForTestFiles } from '../utils/search-pattern' @@ -16,9 +16,9 @@ import { getWorkspaceFilesContext } from './workspace' * NOTE: Does not work with Agent as the underlying API is not available in Agent. * NOTE: Used by the new unit test commands to get context files. */ -export async function getContextFilesForUnitTestCommand(file: URI): Promise { +export async function getContextFilesForUnitTestCommand(file: URI): Promise { return wrapInActiveSpan('commands.context.test', async span => { - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] // exclude any files in the path with e2e, integration, node_modules, or dist const excludePattern = '**/*{e2e,integration,node_modules,dist}*/**' diff --git a/vscode/src/commands/context/workspace.ts b/vscode/src/commands/context/workspace.ts index 868b82ec4b1a..ab9caf17df3a 100644 --- a/vscode/src/commands/context/workspace.ts +++ b/vscode/src/commands/context/workspace.ts @@ -1,4 +1,4 @@ -import { type ContextFile, logError, wrapInActiveSpan } from '@sourcegraph/cody-shared' +import { type ContextItem, logError, wrapInActiveSpan } from '@sourcegraph/cody-shared' import { CancellationTokenSource, workspace } from 'vscode' import { createContextFile } from '../utils/create-context-file' import { getDocText } from '../utils/workspace-files' @@ -16,12 +16,12 @@ export async function getWorkspaceFilesContext( globalPattern: string, excludePattern?: string, maxResults = 5 -): Promise { +): Promise { return wrapInActiveSpan('commands.context.workspace', async span => { // the default exclude pattern excludes dotfiles, node_modules, and snap directories const excluded = excludePattern || '**/{.*,node_modules,snap*}/**' - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] // set cancellation token to time out after 20s const token = new CancellationTokenSource() diff --git a/vscode/src/commands/execute/explain.ts b/vscode/src/commands/execute/explain.ts index ec4d7fa0e206..1dadcacc3df6 100644 --- a/vscode/src/commands/execute/explain.ts +++ b/vscode/src/commands/execute/explain.ts @@ -1,4 +1,4 @@ -import { type ContextFile, displayPath, logDebug } from '@sourcegraph/cody-shared' +import { type ContextItem, displayPath, logDebug } from '@sourcegraph/cody-shared' import { DefaultChatCommands } from '@sourcegraph/cody-shared/src/commands/types' import { defaultCommands } from '.' import type { ChatCommandResult } from '../../main' @@ -30,7 +30,7 @@ async function explainCommand( } // fetches the context file from the current cursor position using getContextFileFromCursor(). - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] const currentSelection = await getContextFileFromCursor() contextFiles.push(...currentSelection) diff --git a/vscode/src/commands/execute/smell.ts b/vscode/src/commands/execute/smell.ts index c98b505d2655..948ab35e1e04 100644 --- a/vscode/src/commands/execute/smell.ts +++ b/vscode/src/commands/execute/smell.ts @@ -1,4 +1,4 @@ -import { type ContextFile, displayPath, logDebug } from '@sourcegraph/cody-shared' +import { type ContextItem, displayPath, logDebug } from '@sourcegraph/cody-shared' import { DefaultChatCommands } from '@sourcegraph/cody-shared/src/commands/types' import { defaultCommands } from '.' import type { ChatCommandResult } from '../../main' @@ -25,7 +25,7 @@ async function smellCommand(span: Span, args?: Partial): Promis prompt = `${prompt} ${args.additionalInstruction}` } - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] const currentSelection = await getContextFileFromCursor() contextFiles.push(...currentSelection) diff --git a/vscode/src/commands/execute/test-case.ts b/vscode/src/commands/execute/test-case.ts index 3e130dcf450e..0a0c0b6e3da4 100644 --- a/vscode/src/commands/execute/test-case.ts +++ b/vscode/src/commands/execute/test-case.ts @@ -1,4 +1,4 @@ -import { type ContextFile, logError } from '@sourcegraph/cody-shared' +import { type ContextItem, logError } from '@sourcegraph/cody-shared' import { DefaultEditCommands } from '@sourcegraph/cody-shared/src/commands/types' import { Range } from 'vscode' import { type ExecuteEditArguments, executeEdit } from '../../edit/execute' @@ -29,7 +29,7 @@ export async function executeTestCaseEditCommand( return } - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] try { const files = await getContextFilesForAddingUnitTestCases(document.uri) diff --git a/vscode/src/commands/execute/test-chat.ts b/vscode/src/commands/execute/test-chat.ts index de17167c656a..a457f3621a5e 100644 --- a/vscode/src/commands/execute/test-chat.ts +++ b/vscode/src/commands/execute/test-chat.ts @@ -1,4 +1,4 @@ -import { type ContextFile, logDebug, logError } from '@sourcegraph/cody-shared' +import { type ContextItem, logDebug, logError } from '@sourcegraph/cody-shared' import { getEditor } from '../../editor/active-editor' import type { ChatCommandResult } from '../../main' import { telemetryService } from '../../services/telemetry' @@ -29,7 +29,7 @@ async function unitTestCommand( const editor = getEditor()?.active const document = editor?.document - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] if (document) { try { diff --git a/vscode/src/commands/execute/test-edit.ts b/vscode/src/commands/execute/test-edit.ts index f543ee40ee08..32ddd6c52084 100644 --- a/vscode/src/commands/execute/test-edit.ts +++ b/vscode/src/commands/execute/test-edit.ts @@ -1,4 +1,4 @@ -import { type ContextFile, logError } from '@sourcegraph/cody-shared' +import { type ContextItem, logError } from '@sourcegraph/cody-shared' import { DefaultEditCommands } from '@sourcegraph/cody-shared/src/commands/types' import { defaultCommands } from '.' import { type ExecuteEditArguments, executeEdit } from '../../edit/execute' @@ -37,7 +37,7 @@ export async function executeTestEditCommand( // Selection will be added by the edit command // Only add context from available test files - const contextFiles: ContextFile[] = [] + const contextFiles: ContextItem[] = [] try { const files = await getContextFilesForUnitTestCommand(document.uri) diff --git a/vscode/src/commands/services/provider.ts b/vscode/src/commands/services/provider.ts index 32db392a0a78..ce48841ca7de 100644 --- a/vscode/src/commands/services/provider.ts +++ b/vscode/src/commands/services/provider.ts @@ -1,4 +1,4 @@ -import { type CodyCommand, type ContextFile, featureFlagProvider } from '@sourcegraph/cody-shared' +import { type CodyCommand, type ContextItem, featureFlagProvider } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { CodyCommandMenuItems } from '..' @@ -92,7 +92,7 @@ export class CommandsProvider implements vscode.Disposable { * Gets the context file content from executing a shell command. * Used for retreiving context for the command field in custom command */ - public async runShell(shell: string): Promise { + public async runShell(shell: string): Promise { return getContextFileFromShell(shell) } diff --git a/vscode/src/commands/services/runner.ts b/vscode/src/commands/services/runner.ts index 4424b6c32f08..fbd5017a0405 100644 --- a/vscode/src/commands/services/runner.ts +++ b/vscode/src/commands/services/runner.ts @@ -5,7 +5,7 @@ import { type ChatEventSource, type CodyCommand, ConfigFeaturesSingleton, - type ContextFile, + type ContextItem, } from '@sourcegraph/cody-shared' import { type ExecuteEditArguments, executeEdit } from '../../edit/execute' @@ -162,7 +162,7 @@ export class CommandRunner implements vscode.Disposable { /** * Combine userContextFiles and context fetched for the command */ - private async getContextFiles(): Promise { + private async getContextFiles(): Promise { const contextConfig = this.command.context this.span.setAttribute('contextConfig', JSON.stringify(contextConfig)) diff --git a/vscode/src/commands/types.ts b/vscode/src/commands/types.ts index 758e3ecd8c24..2f9b57845e93 100644 --- a/vscode/src/commands/types.ts +++ b/vscode/src/commands/types.ts @@ -1,4 +1,4 @@ -import type { ChatEventSource, CodyCommand, ContextFile } from '@sourcegraph/cody-shared' +import type { ChatEventSource, CodyCommand, ContextItem } from '@sourcegraph/cody-shared' /** * The name of the file for configuring Custom Commands. @@ -29,6 +29,6 @@ export interface CodyCommandArgs { // runs the command in chat mode, even if it's an edit command runInChatMode?: boolean // current context to add on top of the command context - userContextFiles?: ContextFile[] + userContextFiles?: ContextItem[] additionalInstruction?: string } diff --git a/vscode/src/commands/utils/create-context-file.ts b/vscode/src/commands/utils/create-context-file.ts index 6edc73b671f6..8b57a88f792f 100644 --- a/vscode/src/commands/utils/create-context-file.ts +++ b/vscode/src/commands/utils/create-context-file.ts @@ -1,9 +1,9 @@ -import { type ContextFile, MAX_CURRENT_FILE_TOKENS, truncateText } from '@sourcegraph/cody-shared' +import { type ContextItem, MAX_CURRENT_FILE_TOKENS, truncateText } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import type { URI } from 'vscode-uri' -export async function createContextFile(file: URI, content: string): Promise { +export async function createContextFile(file: URI, content: string): Promise { try { const truncatedContent = truncateText(content, MAX_CURRENT_FILE_TOKENS) // From line 0 to the end of truncatedContent @@ -15,7 +15,7 @@ export async function createContextFile(file: URI, content: string): Promise { + public async search(query: string): Promise { const results = await this.query(query) if (isError(results)) { throw results diff --git a/vscode/src/edit/execute.ts b/vscode/src/edit/execute.ts index 98d70fb1885e..b364fc1c3bae 100644 --- a/vscode/src/edit/execute.ts +++ b/vscode/src/edit/execute.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' -import type { ChatEventSource, ContextFile, ContextMessage, EditModel } from '@sourcegraph/cody-shared' +import type { ChatEventSource, ContextItem, ContextMessage, EditModel } from '@sourcegraph/cody-shared' import type { FixupTask } from '../non-stop/FixupTask' import type { EditIntent, EditMode } from './types' @@ -9,7 +9,7 @@ export interface ExecuteEditArguments { configuration?: { document?: vscode.TextDocument instruction?: string - userContextFiles?: ContextFile[] + userContextFiles?: ContextItem[] contextMessages?: ContextMessage[] intent?: EditIntent range?: vscode.Range diff --git a/vscode/src/edit/input/get-input.ts b/vscode/src/edit/input/get-input.ts index 5ad25f011d3c..0a21a7f39bc0 100644 --- a/vscode/src/edit/input/get-input.ts +++ b/vscode/src/edit/input/get-input.ts @@ -1,4 +1,4 @@ -import type { ChatEventSource, ContextFile, EditModel } from '@sourcegraph/cody-shared' +import type { ChatEventSource, ContextItem, EditModel } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { ACCOUNT_UPGRADE_URL } from '../../chat/protocol' @@ -22,13 +22,13 @@ import { getTestInputItems } from './get-items/test' import type { EditModelItem, EditRangeItem } from './get-items/types' import { getMatchingContext } from './get-matching-context' import { createQuickPick } from './quick-pick' -import { fetchDocumentSymbols, getLabelForContextFile, getTitleRange, removeAfterLastAt } from './utils' +import { fetchDocumentSymbols, getLabelForContextItem, getTitleRange, removeAfterLastAt } from './utils' interface QuickPickInput { /** The user provided instruction */ instruction: string /** Any user provided context, from @ or @# */ - userContextFiles: ContextFile[] + userContextFiles: ContextItem[] /** The LLM that the user has selected */ model: EditModel /** The range that the user has selected */ @@ -47,7 +47,7 @@ export interface EditInputInitialValues { initialModel: EditModel initialIntent: EditIntent initialInputValue?: string - initialSelectedContextFiles?: ContextFile[] + initialSelectedContextFiles?: ContextItem[] } const PREVIEW_RANGE_DECORATION = vscode.window.createTextEditorDecorationType({ @@ -87,13 +87,13 @@ export const getInput = async ( let activeModelItem = modelItems.find(item => item.model === initialValues.initialModel) // ContextItems to store possible user-provided context - const contextItems = new Map() - const selectedContextItems = new Map() + const contextItems = new Map() + const selectedContextItems = new Map() // Initialize the selectedContextItems with any previous items // This is primarily for edit retries, where a user may want to reuse their context for (const file of initialValues.initialSelectedContextFiles ?? []) { - selectedContextItems.set(getLabelForContextFile(file), file) + selectedContextItems.set(getLabelForContextItem(file), file) } /** diff --git a/vscode/src/edit/input/get-matching-context.ts b/vscode/src/edit/input/get-matching-context.ts index 1a07e00262d9..d548af59c1cb 100644 --- a/vscode/src/edit/input/get-matching-context.ts +++ b/vscode/src/edit/input/get-matching-context.ts @@ -1,8 +1,8 @@ -import type { ContextFile } from '@sourcegraph/cody-shared' +import type { ContextItem } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { getFileContextFiles, getSymbolContextFiles } from '../../editor/utils/editor-context' -import { getLabelForContextFile } from './utils' +import { getLabelForContextItem } from './utils' /* Match strings that end with a '@' followed by any characters except a space */ const MATCHING_CONTEXT_FILE_REGEX = /@(\S+)$/ @@ -17,7 +17,7 @@ interface FixupMatchingContext { key: string /* If present, will override the key shown in the quick pick selector */ shortLabel?: string - file: ContextFile + file: ContextItem } export async function getMatchingContext(instruction: string): Promise { @@ -25,7 +25,7 @@ export async function getMatchingContext(instruction: string): Promise ({ - key: getLabelForContextFile(result), + key: getLabelForContextItem(result), file: result, shortLabel: `${result.kind === 'class' ? '$(symbol-structure)' : '$(symbol-method)'} ${ result.symbolName @@ -42,7 +42,7 @@ export async function getMatchingContext(instruction: string): Promise ({ - key: getLabelForContextFile(result), + key: getLabelForContextItem(result), file: result, })) } diff --git a/vscode/src/edit/input/utils.ts b/vscode/src/edit/input/utils.ts index 4330cc875d93..fc9f1db4a884 100644 --- a/vscode/src/edit/input/utils.ts +++ b/vscode/src/edit/input/utils.ts @@ -1,4 +1,4 @@ -import { type ContextFile, displayPath } from '@sourcegraph/cody-shared' +import { type ContextItem, displayPath } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { QUICK_PICK_ITEM_CHECKED_PREFIX, QUICK_PICK_ITEM_EMPTY_INDENT_PREFIX } from './constants' @@ -16,16 +16,16 @@ export function removeAfterLastAt(str: string): string { } /** - * Returns a string representation of the given ContextFile for use in UI labels. + * Returns a string representation of the given ContextItem for use in UI labels. * Includes the file path and an optional range or symbol specifier. */ -export function getLabelForContextFile(file: ContextFile): string { - const isFileType = file.type === 'file' - const rangeLabel = file.range ? `:${file.range?.start.line}-${file.range?.end.line}` : '' +export function getLabelForContextItem(item: ContextItem): string { + const isFileType = item.type === 'file' + const rangeLabel = item.range ? `:${item.range?.start.line}-${item.range?.end.line}` : '' if (isFileType) { - return `${displayPath(file.uri)}${rangeLabel}` + return `${displayPath(item.uri)}${rangeLabel}` } - return `${displayPath(file.uri)}${rangeLabel}#${file.symbolName}` + return `${displayPath(item.uri)}${rangeLabel}#${item.symbolName}` } /** diff --git a/vscode/src/edit/prompt/context.ts b/vscode/src/edit/prompt/context.ts index 91171c38e68e..33a085add597 100644 --- a/vscode/src/edit/prompt/context.ts +++ b/vscode/src/edit/prompt/context.ts @@ -2,7 +2,7 @@ import type * as vscode from 'vscode' import { type CodyCommand, - type ContextFile, + type ContextItem, type ContextMessage, MAX_CURRENT_FILE_TOKENS, createContextMessageByFile, @@ -17,7 +17,6 @@ import { import type { VSCodeEditor } from '../../editor/vscode-editor' import type { EditIntent } from '../types' -import type { ContextItem } from '../../prompt-builder/types' import { PROMPT_TOPICS } from './constants' import { extractContextItemsFromContextMessages } from './utils' @@ -139,7 +138,7 @@ const getContextFromIntent = async ({ const isAgentTesting = process.env.CODY_SHIM_TESTING === 'true' interface GetContextOptions extends GetContextFromIntentOptions { - userContextFiles: ContextFile[] + userContextFiles: ContextItem[] contextMessages?: ContextMessage[] editor: VSCodeEditor command?: CodyCommand diff --git a/vscode/src/edit/prompt/utils.ts b/vscode/src/edit/prompt/utils.ts index fe5c5de21bae..2d62816bbaad 100644 --- a/vscode/src/edit/prompt/utils.ts +++ b/vscode/src/edit/prompt/utils.ts @@ -1,13 +1,13 @@ import * as vscode from 'vscode' -import type { ContextMessage } from '@sourcegraph/cody-shared' -import type { ContextItem } from '../../prompt-builder/types' +import type { ContextItem, ContextMessage } from '@sourcegraph/cody-shared' type ExtractableContextMessage = Required> & ContextMessage const contextMessageToContextItem = ({ text, file }: ExtractableContextMessage): ContextItem => { return { - text: text, + type: 'file', + content: text, range: file.range ? new vscode.Range( new vscode.Position(file.range.start.line, file.range.start.character), diff --git a/vscode/src/editor/utils/editor-context.test.ts b/vscode/src/editor/utils/editor-context.test.ts index 3116ae17cfe3..24ac5ce38dd5 100644 --- a/vscode/src/editor/utils/editor-context.test.ts +++ b/vscode/src/editor/utils/editor-context.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import * as vscode from 'vscode' import { - type ContextFileFile, + type ContextItemFile, MAX_CURRENT_FILE_TOKENS, ignores, testFileUri, @@ -138,7 +138,7 @@ describe('filterLargeFiles', () => { const largeFile = { uri: vscode.Uri.file('/large-file.txt'), type: 'file', - } as ContextFileFile + } as ContextItemFile vscode.workspace.fs.stat = vi.fn().mockResolvedValueOnce({ size: 1000001, type: vscode.FileType.File, @@ -153,7 +153,7 @@ describe('filterLargeFiles', () => { const binaryFile = { uri: vscode.Uri.file('/binary.bin'), type: 'file', - } as ContextFileFile + } as ContextItemFile vscode.workspace.fs.stat = vi.fn().mockResolvedValueOnce({ size: 100, type: vscode.FileType.SymbolicLink, @@ -168,7 +168,7 @@ describe('filterLargeFiles', () => { const largeTextFile = { uri: vscode.Uri.file('/large-text.txt'), type: 'file', - } as ContextFileFile + } as ContextItemFile vscode.workspace.fs.stat = vi.fn().mockResolvedValueOnce({ size: MAX_CURRENT_FILE_TOKENS * CHARS_PER_TOKEN + 1, type: vscode.FileType.File, diff --git a/vscode/src/editor/utils/editor-context.ts b/vscode/src/editor/utils/editor-context.ts index 22c6b2827e54..4bcf8a46dbf8 100644 --- a/vscode/src/editor/utils/editor-context.ts +++ b/vscode/src/editor/utils/editor-context.ts @@ -5,11 +5,11 @@ import throttle from 'lodash/throttle' import * as vscode from 'vscode' import { - type ContextFile, - type ContextFileFile, type ContextFileSource, - type ContextFileSymbol, type ContextFileType, + type ContextItem, + type ContextItemFile, + type ContextItemSymbol, MAX_CURRENT_FILE_TOKENS, type SymbolKind, displayPath, @@ -52,7 +52,7 @@ export async function getFileContextFiles( query: string, maxResults: number, token: vscode.CancellationToken -): Promise { +): Promise { if (!query.trim()) { return [] } @@ -121,7 +121,7 @@ export async function getFileContextFiles( export async function getSymbolContextFiles( query: string, maxResults = 20 -): Promise { +): Promise { if (!query.trim()) { return [] } @@ -177,7 +177,7 @@ export async function getSymbolContextFiles( * Gets context files for each open editor tab in VS Code. * Filters out large files over 1MB to avoid expensive parsing. */ -export async function getOpenTabsContextFile(): Promise { +export async function getOpenTabsContextFile(): Promise { return await filterLargeFiles( getOpenTabsUris() .filter(uri => !isCodyIgnoredFile(uri)) @@ -192,13 +192,13 @@ function createContextFileFromUri( selectionRange: vscode.Range, kind: SymbolKind, symbolName: string -): ContextFileSymbol[] +): ContextItemSymbol[] function createContextFileFromUri( uri: vscode.Uri, source: ContextFileSource, type: 'file', selectionRange?: vscode.Range -): ContextFileFile[] +): ContextItemFile[] function createContextFileFromUri( uri: vscode.Uri, source: ContextFileSource, @@ -206,7 +206,7 @@ function createContextFileFromUri( selectionRange?: vscode.Range, kind?: SymbolKind, symbolName?: string -): ContextFile[] { +): ContextItem[] { if (isCodyIgnoredFile(uri)) { return [] } @@ -231,7 +231,7 @@ function createContextFileFromUri( ] } -function createContextFileRange(selectionRange: vscode.Range): ContextFile['range'] { +function createContextFileRange(selectionRange: vscode.Range): ContextItem['range'] { return { start: { line: selectionRange.start.line, @@ -248,7 +248,7 @@ function createContextFileRange(selectionRange: vscode.Range): ContextFile['rang * Filters the given context files to remove files larger than 1MB and non-text files. * Sets the title to 'large-file' for files contains more characters than the token limit. */ -export async function filterLargeFiles(contextFiles: ContextFileFile[]): Promise { +export async function filterLargeFiles(contextFiles: ContextItemFile[]): Promise { const filtered = [] for (const cf of contextFiles) { // Remove file larger than 1MB and non-text files diff --git a/vscode/src/editor/vscode-editor.ts b/vscode/src/editor/vscode-editor.ts index 8b92da7c8051..caf02c22a6fe 100644 --- a/vscode/src/editor/vscode-editor.ts +++ b/vscode/src/editor/vscode-editor.ts @@ -5,9 +5,9 @@ import { type ActiveTextEditorDiagnostic, type ActiveTextEditorDiagnosticType, type ActiveTextEditorSelection, - type ActiveTextEditorSelectionRange, type ActiveTextEditorVisibleContent, type Editor, + type RangeData, SURROUNDING_LINES, isCodyIgnoredFile, } from '@sourcegraph/cody-shared' @@ -73,7 +73,7 @@ export class VSCodeEditor implements Editor { public async getTextEditorContentForFile( fileUri: vscode.Uri, - selectionRange?: ActiveTextEditorSelectionRange + selectionRange?: RangeData ): Promise { if (!fileUri) { return undefined @@ -113,7 +113,7 @@ export class VSCodeEditor implements Editor { public getActiveTextEditorDiagnosticsForRange({ start, end, - }: ActiveTextEditorSelectionRange): ActiveTextEditorDiagnostic[] | null { + }: RangeData): ActiveTextEditorDiagnostic[] | null { const activeEditor = this.getActiveTextEditorInstance() if (!activeEditor) { return null diff --git a/vscode/src/local-context/context-ranking.ts b/vscode/src/local-context/context-ranking.ts index 2597fc52ae00..de5672378056 100644 --- a/vscode/src/local-context/context-ranking.ts +++ b/vscode/src/local-context/context-ranking.ts @@ -3,11 +3,10 @@ import * as vscode from 'vscode' import { logDebug } from '../log' import { type ConfigurationWithAccessToken, isDotCom } from '@sourcegraph/cody-shared' -import { type FileURI, isFileURI } from '@sourcegraph/cody-shared' +import { type ContextItem, type FileURI, isFileURI } from '@sourcegraph/cody-shared' import { URI } from 'vscode-uri' import type { RankContextItem, RankerPrediction } from '../jsonrpc/context-ranking-protocol' import type { MessageHandler } from '../jsonrpc/jsonrpc' -import type { ContextItem } from '../prompt-builder/types' import { captureException } from '../services/sentry/sentry' import { CodyEngineService } from './cody-engine' @@ -163,7 +162,7 @@ export class ContextRankingController implements ContextRanker { const rankContextItems = contextItems.map((item, index) => ({ document_id: index, filePath: item.uri?.path ? path.relative(baseRepoPath, item.uri?.path) : '', - content: item.text, + content: item.content ?? '', source: item.source, })) return rankContextItems diff --git a/vscode/src/non-stop/FixupController.ts b/vscode/src/non-stop/FixupController.ts index 3b58f56ae63c..11eb22d23f4e 100644 --- a/vscode/src/non-stop/FixupController.ts +++ b/vscode/src/non-stop/FixupController.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode' import { type ChatEventSource, - type ContextFile, + type ContextItem, type ContextMessage, type EditModel, displayPathBasename, @@ -234,7 +234,7 @@ export class FixupController public async createTask( document: vscode.TextDocument, instruction: string, - userContextFiles: ContextFile[], + userContextFiles: ContextItem[], selectionRange: vscode.Range, intent: EditIntent, mode: EditMode, diff --git a/vscode/src/non-stop/FixupDocumentEditObserver.ts b/vscode/src/non-stop/FixupDocumentEditObserver.ts index 18ea760a0c38..8972f997803d 100644 --- a/vscode/src/non-stop/FixupDocumentEditObserver.ts +++ b/vscode/src/non-stop/FixupDocumentEditObserver.ts @@ -1,30 +1,20 @@ import * as vscode from 'vscode' -import type { Edit, Position, Range } from './diff' +import { type RangeData, toRangeData } from '@sourcegraph/cody-shared' +import type { Edit, Position } from './diff' import type { FixupFileCollection, FixupTextChanged } from './roles' import { type TextChange, updateFixedRange, updateRangeMultipleChanges } from './tracked-range' import { CodyTaskState } from './utils' // This does some thunking to manage the two range types: diff ranges, and // text change ranges. -function updateDiffRange(range: Range, changes: TextChange[]): Range { - return toDiffRange( +function updateDiffRange(range: RangeData, changes: TextChange[]): RangeData { + return toRangeData( updateRangeMultipleChanges(toVsCodeRange(range), changes, { supportRangeAffix: true }) ) } -function toDiffRange(range: vscode.Range): Range { - return { - start: toDiffPosition(range.start), - end: toDiffPosition(range.end), - } -} - -function toDiffPosition(position: vscode.Position): Position { - return { line: position.line, character: position.character } -} - -function toVsCodeRange(range: Range): vscode.Range { +function toVsCodeRange(range: RangeData): vscode.Range { return new vscode.Range(toVsCodePosition(range.start), toVsCodePosition(range.end)) } @@ -33,7 +23,7 @@ function toVsCodePosition(position: Position): vscode.Position { } // Updates the ranges in a diff. -function updateRanges(ranges: Range[], changes: TextChange[]): void { +function updateRanges(ranges: RangeData[], changes: TextChange[]): void { for (let i = 0; i < ranges.length; i++) { ranges[i] = updateDiffRange(ranges[i], changes) } diff --git a/vscode/src/non-stop/FixupTask.ts b/vscode/src/non-stop/FixupTask.ts index 0be76b3cc0f1..7fcea8f8581d 100644 --- a/vscode/src/non-stop/FixupTask.ts +++ b/vscode/src/non-stop/FixupTask.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' -import type { ChatEventSource, ContextFile, ContextMessage, EditModel } from '@sourcegraph/cody-shared' +import type { ChatEventSource, ContextItem, ContextMessage, EditModel } from '@sourcegraph/cody-shared' import type { EditIntent, EditMode } from '../edit/types' @@ -53,7 +53,7 @@ export class FixupTask { */ public fixupFile: FixupFile, public readonly instruction: string, - public readonly userContextFiles: ContextFile[], + public readonly userContextFiles: ContextItem[], /* The intent of the edit, derived from the source of the command. */ public readonly intent: EditIntent, public selectionRange: vscode.Range, diff --git a/vscode/src/non-stop/diff.ts b/vscode/src/non-stop/diff.ts index 5a5ae33fa10c..fca1921c8fd7 100644 --- a/vscode/src/non-stop/diff.ts +++ b/vscode/src/non-stop/diff.ts @@ -32,6 +32,8 @@ function dumpProgram(program: Uint16Array, ops: Op[], a: string, b: string): voi } */ +import type { RangeData } from '@sourcegraph/cody-shared' + function render(ch: string): string { return ch === '\n' ? '@' : ch } @@ -219,14 +221,9 @@ export interface Position { character: number } -export interface Range { - start: Position - end: Position -} - export interface Edit { text: string - range: Range + range: RangeData } export interface Diff { @@ -235,9 +232,9 @@ export interface Diff { mergedText: string | undefined // TODO: We can use the presence of mergedText to indicate clean clean: boolean - conflicts: Range[] + conflicts: RangeData[] edits: Edit[] - highlights: Range[] + highlights: RangeData[] } // Rolls over characters in text and computes the updated position to the end diff --git a/vscode/src/prompt-builder/index.ts b/vscode/src/prompt-builder/index.ts index eaf2b9cb819b..04da63f4b2bd 100644 --- a/vscode/src/prompt-builder/index.ts +++ b/vscode/src/prompt-builder/index.ts @@ -1,6 +1,5 @@ -import { type Message, isCodyIgnoredFile } from '@sourcegraph/cody-shared' +import { type ContextItem, type Message, isCodyIgnoredFile } from '@sourcegraph/cody-shared' import type { MessageWithContext } from '../chat/chat-view/SimpleChatModel' -import type { ContextItem } from './types' import { contextItemId, renderContextItem } from './utils' const isAgentTesting = process.env.CODY_SHIM_TESTING === 'true' diff --git a/vscode/src/prompt-builder/types.ts b/vscode/src/prompt-builder/types.ts index d1a13206e995..9b9d83583e68 100644 --- a/vscode/src/prompt-builder/types.ts +++ b/vscode/src/prompt-builder/types.ts @@ -2,10 +2,11 @@ import type * as vscode from 'vscode' import type { ContextFileSource } from '@sourcegraph/cody-shared' +// TODO(sqs) export interface ContextItem { uri: vscode.Uri range?: vscode.Range - text: string + content: string source?: ContextFileSource repoName?: string revision?: string diff --git a/vscode/src/prompt-builder/utils.ts b/vscode/src/prompt-builder/utils.ts index df2179fac84d..4b5b38f26c72 100644 --- a/vscode/src/prompt-builder/utils.ts +++ b/vscode/src/prompt-builder/utils.ts @@ -1,4 +1,5 @@ import { + type ContextItem, type Message, ProgrammingLanguage, languageFromFilename, @@ -8,7 +9,6 @@ import { populateMarkdownContextTemplate, } from '@sourcegraph/cody-shared' import { URI } from 'vscode-uri' -import type { ContextItem } from './types' export function contextItemId(contextItem: ContextItem): string { return contextItem.range @@ -18,24 +18,24 @@ export function contextItemId(contextItem: ContextItem): string { export function renderContextItem(contextItem: ContextItem): Message[] { // Do not create context item for empty file - if (!contextItem.text?.trim()?.length) { + if (!contextItem.content?.trim()?.length) { return [] } let messageText: string const uri = contextItem.source === 'unified' ? URI.parse(contextItem.title || '') : contextItem.uri if (contextItem.source === 'selection') { - messageText = populateCurrentSelectedCodeContextTemplate(contextItem.text, uri) + messageText = populateCurrentSelectedCodeContextTemplate(contextItem.content, uri) } else if (contextItem.source === 'editor') { // This template text works best with prompts in our commands // Using populateCodeContextTemplate here will cause confusion to Cody const templateText = 'Codebase context from file path {fileName}: ' - messageText = populateContextTemplateFromText(templateText, contextItem.text, uri) + messageText = populateContextTemplateFromText(templateText, contextItem.content, uri) } else if (contextItem.source === 'terminal') { - messageText = contextItem.text + messageText = contextItem.content } else if (languageFromFilename(uri) === ProgrammingLanguage.Markdown) { - messageText = populateMarkdownContextTemplate(contextItem.text, uri, contextItem.repoName) + messageText = populateMarkdownContextTemplate(contextItem.content, uri, contextItem.repoName) } else { - messageText = populateCodeContextTemplate(contextItem.text, uri, contextItem.repoName) + messageText = populateCodeContextTemplate(contextItem.content, uri, contextItem.repoName) } return [ { speaker: 'human', text: messageText }, diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index 2f3dda5975f4..5548f5cbd6d4 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -6,7 +6,7 @@ import { type ChatInputHistory, type ChatMessage, type Configuration, - type ContextFile, + type ContextItem, type EnhancedContextContextT, GuardrailsPost, type ModelProvider, @@ -50,7 +50,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc const [userHistory, setUserHistory] = useState([]) const [chatIDHistory, setChatIDHistory] = useState([]) - const [contextSelection, setContextSelection] = useState(null) + const [contextSelection, setContextSelection] = useState(null) const [errorMessages, setErrorMessages] = useState([]) const [isTranscriptError, setIsTranscriptError] = useState(false) diff --git a/vscode/webviews/Chat.tsx b/vscode/webviews/Chat.tsx index 7b4ff6b1318b..a28e6074b2c3 100644 --- a/vscode/webviews/Chat.tsx +++ b/vscode/webviews/Chat.tsx @@ -7,7 +7,7 @@ import classNames from 'classnames' import type { ChatInputHistory, ChatMessage, - ContextFile, + ContextItem, Guardrails, ModelProvider, TelemetryService, @@ -51,8 +51,8 @@ interface ChatboxProps { vscodeAPI: VSCodeWrapper telemetryService: TelemetryService isTranscriptError: boolean - contextSelection?: ContextFile[] | null - setContextSelection: (context: ContextFile[] | null) => void + contextSelection?: ContextItem[] | null + setContextSelection: (context: ContextItem[] | null) => void setChatModels?: (models: ModelProvider[]) => void chatModels?: ModelProvider[] userInfo: UserAccountInfo @@ -90,7 +90,7 @@ export const Chat: React.FunctionComponent const addEnhancedContext = useEnhancedContextEnabled() const onEditSubmit = useCallback( - (text: string, index: number, contextFiles: ContextFile[]) => { + (text: string, index: number, contextFiles: ContextItem[]) => { vscodeAPI.postMessage({ command: 'edit', index, @@ -103,7 +103,7 @@ export const Chat: React.FunctionComponent ) const onSubmit = useCallback( - (text: string, submitType: WebviewChatSubmitType, contextFiles?: Map) => { + (text: string, submitType: WebviewChatSubmitType, contextFiles?: Map) => { // loop the added contextFiles to: // 1. check if the key still exists in the text // 2. remove the ones not present