From e7a420bba60bfea3eb24156709f1e11ef5ac4dff Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Tue, 2 Jul 2024 18:03:51 -0700 Subject: [PATCH 01/34] WIP --- lib/shared/src/models/index.ts | 100 ++++++++++++++++-- lib/shared/src/sourcegraph-api/rest/client.ts | 91 +++++++++++----- vscode/webviews/App.tsx | 12 +++ vscode/webviews/Chat.tsx | 3 + .../human/editor/toolbar/Toolbar.tsx | 5 +- vscode/webviews/chat/fixtures.ts | 1 + .../modelSelectField/ModelSelectField.tsx | 10 +- 7 files changed, 176 insertions(+), 46 deletions(-) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 1d00a2d642c..a8d820a34f1 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1,8 +1,38 @@ import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' -import type { ModelContextWindow, ModelUsage } from './types' +import { type ModelContextWindow, ModelUsage } from './types' import { getModelInfo } from './utils' +export type ModelId = string +export type ApiVersionId = string +export type ProviderId = string + +export type ModelRef = `${ProviderId}::${ApiVersionId}::${ModelId}` + +export type ModelCapability = 'chat' | 'autocomplete' +export type ModelCategory = 'accuracy' | 'balanced' | 'speed' +export type ModelStatus = 'experimental' | 'beta' | 'stable' | 'deprecated' +export type ModelTier = 'free' | 'pro' | 'enterprise' + +export interface ContextWindow { + maxInputTokens: number + maxOutputTokens: number +} + +export interface ServerModel { + modelRef: ModelRef + displayName: string + modelName: string + capabilities: ModelCapability[] + category: ModelCategory + status: ModelStatus + tier: ModelTier + + contextWindow: ContextWindow + + clientSideConfig?: unknown +} + /** * Model describes an LLM model and its capabilities. */ @@ -15,10 +45,6 @@ export class Model { // Whether the model is only available to Pro users public codyProOnly = false - // The name of the provider of the model, e.g. "Anthropic" - public provider: string - // The title of the model, e.g. "Claude 3 Sonnet" - public readonly title: string // A deprecated model can be used (to not break agent) but won't be rendered // in the UI public deprecated = false @@ -57,14 +83,61 @@ export class Model { */ apiEndpoint?: string }, - public readonly uiGroup?: string + public readonly uiGroup?: string, + + public readonly tier?: 'free' | 'pro' | 'enterprise', + + // The name of the provider of the model, e.g. "Anthropic" + public provider?: string, + // The title of the model, e.g. "Claude 3 Sonnet" + public readonly title?: string ) { - const { provider, title } = getModelInfo(model) - this.provider = provider - this.title = title + if (!provider || !title) { + const info = getModelInfo(model) + this.provider = provider ?? info.provider + this.title = title ?? info.title + } + } + + // HACK: Constructor override allowing you to supply the title directly, + // so it can be different. + static fromApi({ + modelRef, + displayName, + capabilities, + category, + tier, + clientSideConfig, + contextWindow = { + maxInputTokens: CHAT_INPUT_TOKEN_BUDGET, + maxOutputTokens: CHAT_OUTPUT_TOKEN_BUDGET, + }, + }: ServerModel) { + // BUG: There is data loss here and the potential for ambiguity. + // BUG: We are assuming the modelRef is valid, but it might not be. + const [providerId, _, modelId] = modelRef.split('::', 3) + + return new Model( + modelId, + capabilities.flatMap(capabilityToUsage), + { + input: contextWindow.maxInputTokens, + output: contextWindow.maxOutputTokens, + }, + // @ts-ignore + clientSideConfig, + category, + tier, + providerId, + displayName + ) } } +export function isNewStyleEnterpriseModel(model: Model): boolean { + return model.tier === 'enterprise' +} + /** * ModelsService is the component responsible for keeping track of which models * are supported on the backend, which ones are available based on the user's @@ -173,3 +246,12 @@ export class ModelsService { throw new Error(`${errorMessage} Available models: ${modelsList}`) } } + +export function capabilityToUsage(capability: ModelCapability): ModelUsage[] { + switch (capability) { + case 'autocomplete': + return [] + case 'chat': + return [ModelUsage.Chat, ModelUsage.Edit] + } +} diff --git a/lib/shared/src/sourcegraph-api/rest/client.ts b/lib/shared/src/sourcegraph-api/rest/client.ts index 6d1394070e4..bdeb71b7255 100644 --- a/lib/shared/src/sourcegraph-api/rest/client.ts +++ b/lib/shared/src/sourcegraph-api/rest/client.ts @@ -1,8 +1,6 @@ -import { Model } from '../../models/index' +import { Model, type ServerModel } from '../../models/index' import { fetch } from '../../fetch' - -import { type ModelContextWindow, ModelUsage } from '../../models/types' import { addTraceparent, wrapInActiveSpan } from '../../tracing' import { addCustomUserAgent, verifyResponseCode } from '../graphql/client' @@ -29,7 +27,7 @@ export class RestClient { // Make an authenticated HTTP request to the Sourcegraph instance. // "name" is a developer-friendly term to label the request's trace span. - private getRequest(name: string, urlSuffix: string): Promise { + public getRequest(name: string, urlSuffix: string): Promise { const headers = new Headers() headers.set('Authorization', `token ${this.accessToken}`) addCustomUserAgent(headers) @@ -64,35 +62,70 @@ export class RestClient { // // NOTE: This API endpoint hasn't shippeted yet, and probably won't work for you. // Also, the URL definitely will change. - const serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') + // const serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') + const serverSideConfig = testModels // TODO(PRIME-323): Do a proper review of the data model we will use to describe // server-side configuration. Once complete, it should match the data types we // use in this repo exactly. Until then, we need to map the "server-side" model // types, to the `Model` types used by Cody clients. - const availableModels: Model[] = [] - const serverModels = serverSideConfig.models as any[] - for (const serverModel of serverModels) { - const serverContextWindow = serverModel.contextWindow - const convertedContextWindow: ModelContextWindow = { - input: serverContextWindow.maxInputTokens, - output: serverContextWindow.maxOutputTokens, - context: undefined, // Not yet captured in in the schema. - } - - const convertedModel = new Model( - // The Model type expects the `model` field to contain both the provider - // and model name, whereas the server-side schema has a more nuanced view. - // See PRIME-282. - `${serverModel.provider}/${serverModel.model}`, - [ModelUsage.Chat, ModelUsage.Edit], - convertedContextWindow, - // client-side config not captured in the schema yet. - undefined - ) - availableModels.push(convertedModel) - } - - return availableModels + return serverSideConfig.models.map(Model.fromApi) } } + +const testModels = { + schemaVersion: '1.0', + revision: '-', + providers: [ + { + id: 'anthropic', + displayName: 'Provider "anthropic"', + }, + ], + models: [ + { + modelRef: 'anthropic::unknown::anthropic.claude-3-opus-20240229-v1_0', + displayName: 'anthropic.claude-3-opus-20240229-v1_0', + modelName: 'anthropic.claude-3-opus-20240229-v1_0', + capabilities: ['autocomplete', 'chat'], + category: 'balanced', + status: 'stable', + tier: 'enterprise', + contextWindow: { + maxInputTokens: 9000, + maxOutputTokens: 4000, + }, + }, + { + modelRef: 'anthropic::unknown::anthropic.claude-instant-v1', + displayName: 'anthropic.claude-instant-v1', + modelName: 'anthropic.claude-instant-v1', + capabilities: ['autocomplete', 'chat'], + category: 'balanced', + status: 'stable', + tier: 'enterprise', + contextWindow: { + maxInputTokens: 9000, + maxOutputTokens: 4000, + }, + }, + { + modelRef: 'anthropic::unknown::amazon.titan-text-lite-v1', + displayName: 'amazon.titan-text-lite-v1', + modelName: 'amazon.titan-text-lite-v1', + capabilities: ['autocomplete', 'chat'], + category: 'balanced', + status: 'stable', + tier: 'enterprise', + contextWindow: { + maxInputTokens: 9000, + maxOutputTokens: 4000, + }, + }, + ] as ServerModel[], + defaultModels: { + chat: 'anthropic::unknown::amazon.titan-text-lite-v1', + fastChat: 'anthropic::unknown::anthropic.claude-3-opus-20240229-v1_0', + codeCompletion: 'anthropic::unknown::anthropic.claude-instant-v1', + }, +} diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index 73a7a9f6b89..d5b4ce8abdc 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -15,6 +15,7 @@ import type { UserAccountInfo } from './Chat' import type { AuthMethod, ConfigurationSubsetForWebview, LocalEnv } from '../src/chat/protocol' +import { isNewStyleEnterpriseModel } from '@sourcegraph/cody-shared/src/models' import { Chat } from './Chat' import { LoadingPage } from './LoadingPage' import type { View } from './NavBar' @@ -97,6 +98,8 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc // Receive this value from the extension backend to make it work // with E2E tests where change the DOTCOM_URL via the env variable TESTING_DOTCOM_URL. isDotComUser: message.authStatus.isDotCom, + // Default to assuming they are a single model enterprise + isOldStyleEnterprise: !message.authStatus.isDotCom, user: message.authStatus, }) setView(message.authStatus.isLoggedIn ? 'chat' : 'login') @@ -130,6 +133,15 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc break case 'chatModels': setChatModels(message.models) + setUserAccountInfo( + info => + info && { + ...info, + isOldStyleEnterprise: + !info.isDotComUser && + !message.models.some(isNewStyleEnterpriseModel), + } + ) break case 'attribution': if (message.attribution) { diff --git a/vscode/webviews/Chat.tsx b/vscode/webviews/Chat.tsx index 75eba2fe743..be638acac83 100644 --- a/vscode/webviews/Chat.tsx +++ b/vscode/webviews/Chat.tsx @@ -193,6 +193,9 @@ export const Chat: React.FunctionComponent export interface UserAccountInfo { isDotComUser: boolean isCodyProUser: boolean + // When true, the user is on an enterprise instance that has not upgraded to + // allow multiple LLM selections + isOldStyleEnterprise: boolean user: Pick } diff --git a/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx b/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx index 27aedbe6812..0e4ee2f1f31 100644 --- a/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx +++ b/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx @@ -99,9 +99,8 @@ const ModelSelectFieldToolbarItem: FunctionComponent<{ return ( !!chatModels?.length && - onCurrentChatModelChange && - userInfo && - userInfo.isDotComUser && ( + (userInfo?.isDotComUser || !userInfo?.isOldStyleEnterprise) && + onCurrentChatModelChange && ( void - userInfo: Pick + userInfo: Pick onCloseByEscape?: () => void className?: string @@ -86,7 +86,7 @@ export const ModelSelectField: React.FunctionComponent<{ [telemetryRecorder.recordEvent, showCodyProBadge, parentOnModelSelect, isCodyProUser] ) - const readOnly = !userInfo.isDotComUser + const readOnly = userInfo.isOldStyleEnterprise const onOpenChange = useCallback( (open: boolean): void => { @@ -297,10 +297,10 @@ const GROUP_ORDER = [ type ModelAvailability = 'available' | 'needs-cody-pro' | 'not-selectable-on-enterprise' function modelAvailability( - userInfo: Pick, + userInfo: Pick, model: Model ): ModelAvailability { - if (!userInfo.isDotComUser) { + if (!userInfo.isDotComUser && userInfo.isOldStyleEnterprise) { return 'not-selectable-on-enterprise' } if (model.codyProOnly && !userInfo.isCodyProUser) { @@ -314,7 +314,7 @@ const ModelTitleWithIcon: FunctionComponent<{ showIcon?: boolean showProvider?: boolean modelAvailability?: ModelAvailability -}> = ({ model, showIcon, showProvider, modelAvailability }) => ( +}> = ({ model, showIcon, modelAvailability }) => ( Date: Wed, 3 Jul 2024 12:38:48 -0700 Subject: [PATCH 02/34] refactor: add model tags and remove deprecated models - Add ModelTag enum to categorize models - Remove deprecated models from model options - Update ModelSelectField to only show non-deprecated models TODO: - replace uiGroup with tags - remove codyProOnly & uiGroupfields & usage from Model class --- lib/shared/src/llm-providers/ollama/utils.ts | 6 +- lib/shared/src/models/dotcom.ts | 57 ++++--------------- lib/shared/src/models/index.ts | 10 ++-- lib/shared/src/models/tags.ts | 21 +++++++ vscode/src/edit/input/get-items/model.ts | 3 - vscode/src/models/modelMigrator.ts | 39 +++++++++++-- vscode/src/models/sync.ts | 8 ++- .../ModelSelectField.story.tsx | 3 +- .../modelSelectField/ModelSelectField.tsx | 17 +++--- 9 files changed, 92 insertions(+), 72 deletions(-) create mode 100644 lib/shared/src/models/tags.ts diff --git a/lib/shared/src/llm-providers/ollama/utils.ts b/lib/shared/src/llm-providers/ollama/utils.ts index 1c50ae9e7bf..16bcb277f3c 100644 --- a/lib/shared/src/llm-providers/ollama/utils.ts +++ b/lib/shared/src/llm-providers/ollama/utils.ts @@ -1,6 +1,7 @@ import ollama from 'ollama/browser' import { OLLAMA_DEFAULT_CONTEXT_WINDOW } from '.' -import { Model, ModelUIGroup, ModelUsage } from '../..' +import { Model, ModelUsage } from '../..' +import { ModelTag } from '../../models/tags' import { CHAT_OUTPUT_TOKEN_BUDGET } from '../../token/constants' /** * Fetches available Ollama models from the Ollama server. @@ -16,7 +17,8 @@ export async function fetchLocalOllamaModels(): Promise { output: CHAT_OUTPUT_TOKEN_BUDGET, }, undefined, - ModelUIGroup.Ollama + undefined, + [ModelTag.Ollama, ModelTag.Local] ) ) } diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 6cc72c5bdc4..eb67eafc26f 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -5,6 +5,7 @@ import { EXTENDED_CHAT_INPUT_TOKEN_BUDGET, EXTENDED_USER_CONTEXT_TOKEN_BUDGET, } from '../token/constants' +import { ModelTag } from './tags' import { type ModelContextWindow, ModelUsage } from './types' import { ModelUIGroup } from './utils' @@ -41,8 +42,8 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Balanced, + tags: [ModelTag.Free, ModelTag.Balanced], }, { title: 'Claude 3.5 Sonnet', @@ -53,8 +54,8 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Accuracy, + tags: [ModelTag.Free, ModelTag.Recommended, ModelTag.Accuracy], }, { title: 'Claude 3 Opus', @@ -65,8 +66,8 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Accuracy, + tags: [ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], }, { title: 'Claude 3 Haiku', @@ -76,8 +77,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Speed, + tags: [ModelTag.Free, ModelTag.Speed], }, // -------------------------------- @@ -92,8 +93,8 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Accuracy, + tags: [ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], }, { title: 'GPT-4 Turbo', @@ -103,8 +104,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Balanced, + tags: [ModelTag.Pro, ModelTag.Accuracy], }, { title: 'GPT-3.5 Turbo', @@ -114,8 +115,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Speed, + tags: [ModelTag.Free, ModelTag.Speed], }, // -------------------------------- @@ -129,8 +130,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Accuracy, + tags: [ModelTag.Free, ModelTag.Accuracy], }, { title: 'Gemini 1.5 Flash', @@ -140,8 +141,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Speed, + tags: [ModelTag.Free, ModelTag.Speed], }, // TODO (tom) Improve prompt for Mixtral + Edit to see if we can use it there too. @@ -153,8 +154,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: false, usage: [ModelUsage.Chat], contextWindow: basicContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Speed, + tags: [ModelTag.Free, ModelTag.Speed], }, { title: 'Mixtral 8x22B', @@ -164,42 +165,8 @@ export const DEFAULT_DOT_COM_MODELS = [ codyProOnly: false, usage: [ModelUsage.Chat], contextWindow: basicContextWindow, - deprecated: false, uiGroup: ModelUIGroup.Accuracy, - }, - - // -------------------------------- - // Deprecated models - // -------------------------------- - { - title: 'Claude 2.0', - model: 'anthropic/claude-2.0', - provider: 'Anthropic', - default: false, - codyProOnly: true, - usage: [ModelUsage.Chat, ModelUsage.Edit], - contextWindow: basicContextWindow, - deprecated: true, - }, - { - title: 'Claude 2.1', - model: 'anthropic/claude-2.1', - provider: 'Anthropic', - default: false, - codyProOnly: true, - usage: [ModelUsage.Chat, ModelUsage.Edit], - contextWindow: basicContextWindow, - deprecated: true, - }, - { - title: 'Claude Instant', - model: 'anthropic/claude-instant-1.2', - provider: 'Anthropic', - default: false, - codyProOnly: true, - usage: [ModelUsage.Chat, ModelUsage.Edit], - contextWindow: basicContextWindow, - deprecated: true, + tags: [ModelTag.Free, ModelTag.Accuracy], }, ] as const satisfies Model[] diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 1d00a2d642c..02e6401c59a 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1,5 +1,6 @@ import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' +import type { ModelTag } from './tags' import type { ModelContextWindow, ModelUsage } from './types' import { getModelInfo } from './utils' @@ -19,9 +20,6 @@ export class Model { public provider: string // The title of the model, e.g. "Claude 3 Sonnet" public readonly title: string - // A deprecated model can be used (to not break agent) but won't be rendered - // in the UI - public deprecated = false constructor( /** @@ -57,7 +55,11 @@ export class Model { */ apiEndpoint?: string }, - public readonly uiGroup?: string + public readonly uiGroup?: string, + /** + * The tags assigned for categorizing the model. + */ + public readonly tags: ModelTag[] = [] ) { const { provider, title } = getModelInfo(model) this.provider = provider diff --git a/lib/shared/src/models/tags.ts b/lib/shared/src/models/tags.ts new file mode 100644 index 00000000000..ba30816ef7c --- /dev/null +++ b/lib/shared/src/models/tags.ts @@ -0,0 +1,21 @@ +export enum ModelTag { + Accuracy = 'accuracy', + Speed = 'speed', + Balanced = 'balanced', + + Recommended = 'recommended', + Deprecated = 'deprecated', + + Dev = 'dev', + New = 'new', + Experimental = 'experimental', + Preview = 'preview', + + Pro = 'pro', + Free = 'free', + Enterprise = 'enterprise', + Local = 'local', + BYOK = 'byok', + + Ollama = 'ollama', +} diff --git a/vscode/src/edit/input/get-items/model.ts b/vscode/src/edit/input/get-items/model.ts index 1db2b95c721..c2910f29b0c 100644 --- a/vscode/src/edit/input/get-items/model.ts +++ b/vscode/src/edit/input/get-items/model.ts @@ -28,9 +28,6 @@ const getModelProviderIcon = (provider: string): string => { export const getModelOptionItems = (modelOptions: Model[], isCodyPro: boolean): EditModelItem[] => { const allOptions = modelOptions .map(modelOption => { - if (modelOption.deprecated) { - return - } const icon = getModelProviderIcon(modelOption.provider) return { label: `${QUICK_PICK_ITEM_EMPTY_INDENT_PREFIX} ${icon} ${modelOption.title}`, diff --git a/vscode/src/models/modelMigrator.ts b/vscode/src/models/modelMigrator.ts index 8690407da4f..c6a3962371b 100644 --- a/vscode/src/models/modelMigrator.ts +++ b/vscode/src/models/modelMigrator.ts @@ -1,13 +1,40 @@ -import { ModelsService, getDotComDefaultModels } from '@sourcegraph/cody-shared' +import { type Model, ModelUsage, ModelsService } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { isRunningInsideAgent } from '../jsonrpc/isRunningInsideAgent' import { localStorage } from '../services/LocalStorageProvider' -const deprecatedModelSet = new Set( - getDotComDefaultModels() - .filter(m => m.deprecated) - .map(m => m.model) -) +const DEPRECATED_DOT_COM_MODELS = [ + { + title: 'Claude 2.0', + model: 'anthropic/claude-2.0', + provider: 'Anthropic', + default: false, + codyProOnly: true, + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: { input: 0, output: 0 }, + }, + { + title: 'Claude 2.1', + model: 'anthropic/claude-2.1', + provider: 'Anthropic', + default: false, + codyProOnly: true, + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: { input: 0, output: 0 }, + }, + { + title: 'Claude Instant', + model: 'anthropic/claude-instant-1.2', + provider: 'Anthropic', + default: false, + codyProOnly: true, + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: { input: 0, output: 0 }, + }, +] as Model[] + +const deprecatedModelSet = new Set(DEPRECATED_DOT_COM_MODELS.map(m => m.model)) + export function migrateAndNotifyForOutdatedModels(model: string | null): string | null { if (!model || isRunningInsideAgent() || !deprecatedModelSet.has(model)) { return model diff --git a/vscode/src/models/sync.ts b/vscode/src/models/sync.ts index 54c9cd9b445..bcb1622cc8c 100644 --- a/vscode/src/models/sync.ts +++ b/vscode/src/models/sync.ts @@ -9,6 +9,7 @@ import { RestClient, getDotComDefaultModels, } from '@sourcegraph/cody-shared' +import { ModelTag } from '@sourcegraph/cody-shared/src/models/tags' import * as vscode from 'vscode' import { secretStorage } from '../services/SecretStorageProvider' import { getEnterpriseContextWindow } from './utils' @@ -74,7 +75,8 @@ export async function syncModels(authStatus: AuthStatus): Promise { authStatus?.configOverwrites ), undefined, - ModelUIGroup.Enterprise + ModelUIGroup.Enterprise, + [ModelTag.Enterprise] ), ]) } else { @@ -116,7 +118,9 @@ export function registerModelsFromVSCodeConfiguration() { `${m.provider}/${m.model}`, [ModelUsage.Chat, ModelUsage.Edit], { input: m.inputTokens ?? CHAT_INPUT_TOKEN_BUDGET, output: m.outputTokens ?? ANSWER_TOKENS }, - { apiKey: m.apiKey, apiEndpoint: m.apiEndpoint } + { apiKey: m.apiKey, apiEndpoint: m.apiEndpoint }, + undefined, + [ModelTag.Dev, ModelTag.Experimental] ) models.push(provider) } diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx index c702d0b5ae5..fa11dcf0300 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx @@ -3,6 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react' import { VSCodeStandaloneComponent } from '../../storybook/VSCodeStoryDecorator' import { type Model, ModelUIGroup, ModelUsage, getDotComDefaultModels } from '@sourcegraph/cody-shared' +import { ModelTag } from '@sourcegraph/cody-shared/src/models/tags' import { useArgs } from '@storybook/preview-api' import { ModelSelectField } from './ModelSelectField' @@ -15,9 +16,9 @@ const MODELS: Model[] = [ codyProOnly: false, contextWindow: { input: 100, output: 100 }, default: false, - deprecated: false, usage: [ModelUsage.Chat], uiGroup: ModelUIGroup.Ollama, + tags: [ModelTag.Ollama, ModelTag.Local, ModelTag.Dev], }, ] diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx index 3a4951d18b5..a285c49bdcb 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx @@ -43,8 +43,7 @@ export const ModelSelectField: React.FunctionComponent<{ }) => { const telemetryRecorder = useTelemetryRecorder() - const usableModels = useMemo(() => models.filter(m => !m.deprecated), [models]) - const selectedModel = usableModels.find(m => m.default) ?? usableModels[0] + const selectedModel = models.find(m => m.default) ?? models[0] const isCodyProUser = userInfo.isDotComUser && userInfo.isCodyProUser const isEnterpriseUser = !userInfo.isDotComUser @@ -101,17 +100,17 @@ export const ModelSelectField: React.FunctionComponent<{ telemetryRecorder.recordEvent('cody.modelSelector', 'open', { metadata: { isCodyProUser: isCodyProUser ? 1 : 0, - totalModels: usableModels.length, + totalModels: models.length, }, }) } }, - [telemetryRecorder.recordEvent, isCodyProUser, usableModels.length] + [telemetryRecorder.recordEvent, isCodyProUser, models.length] ) const options = useMemo( () => - usableModels.map(m => { + models.map(m => { const availability = modelAvailability(userInfo, m) return { value: m.model, @@ -135,7 +134,7 @@ export const ModelSelectField: React.FunctionComponent<{ : `${m.title} by ${m.provider}`, } satisfies SelectListOption }), - [usableModels, userInfo] + [models, userInfo] ) const optionsByGroup: { group: string; options: SelectListOption[] }[] = useMemo(() => { const groups = new Map() @@ -167,9 +166,9 @@ export const ModelSelectField: React.FunctionComponent<{ const onChange = useCallback( (value: string | undefined) => { - onModelSelect(usableModels.find(m => m.model === value)!) + onModelSelect(models.find(m => m.model === value)!) }, - [onModelSelect, usableModels] + [onModelSelect, models] ) const onKeyDown = useCallback( @@ -181,7 +180,7 @@ export const ModelSelectField: React.FunctionComponent<{ [onCloseByEscape] ) - if (!usableModels.length || usableModels.length < 1) { + if (!models.length || models.length < 1) { return null } From 0f502583f16acfa7680b78d870013e3e0557b6d6 Mon Sep 17 00:00:00 2001 From: Beatrix Date: Wed, 3 Jul 2024 13:37:54 -0700 Subject: [PATCH 03/34] remove codyProOnly and uiGroup --- lib/shared/src/index.ts | 2 +- lib/shared/src/llm-providers/clients.ts | 7 +- lib/shared/src/llm-providers/ollama/utils.ts | 3 +- lib/shared/src/models/dotcom.ts | 39 ++------ lib/shared/src/models/index.ts | 7 +- lib/shared/src/models/tags.ts | 13 ++- lib/shared/src/models/utils.ts | 13 +-- vscode/src/edit/input/get-items/model.ts | 3 +- vscode/src/models/modelMigrator.ts | 3 - vscode/src/models/sync.test.ts | 4 +- vscode/src/models/sync.ts | 3 - .../ModelSelectField.story.tsx | 6 +- .../modelSelectField/ModelSelectField.tsx | 95 ++++++++++--------- 13 files changed, 84 insertions(+), 114 deletions(-) diff --git a/lib/shared/src/index.ts b/lib/shared/src/index.ts index a73b7dad87f..04f71748b88 100644 --- a/lib/shared/src/index.ts +++ b/lib/shared/src/index.ts @@ -10,10 +10,10 @@ export { type ModelContextWindow, } from './models/types' export { getDotComDefaultModels } from './models/dotcom' +export { ModelTag } from './models/tags' export { getProviderName, getModelInfo, - ModelUIGroup, } from './models/utils' export { BotResponseMultiplexer } from './chat/bot-response-multiplexer' export { ChatClient } from './chat/chat' diff --git a/lib/shared/src/llm-providers/clients.ts b/lib/shared/src/llm-providers/clients.ts index b1e39f2512a..12b912c7667 100644 --- a/lib/shared/src/llm-providers/clients.ts +++ b/lib/shared/src/llm-providers/clients.ts @@ -1,6 +1,7 @@ import type { ChatNetworkClient, ChatNetworkClientParams } from '.' -import { ModelUIGroup, googleChatClient, groqChatClient, ollamaChatClient } from '..' +import { googleChatClient, groqChatClient, ollamaChatClient } from '..' import { type Model, ModelsService } from '../models' +import { ModelTag } from '../models/tags' import { anthropicChatClient } from './anthropic/chat-client' export async function useCustomChatClient({ @@ -34,7 +35,5 @@ export async function useCustomChatClient({ } function isCodyGatewayModel(model: Model): boolean { - // Google models with a UI group are Cody Gateway models. - // TODO (bee) Add new labels to make identifying Cody Gateway models easier. - return model.uiGroup !== undefined && model.uiGroup !== ModelUIGroup.Ollama + return model.tags.includes(ModelTag.Gateway) } diff --git a/lib/shared/src/llm-providers/ollama/utils.ts b/lib/shared/src/llm-providers/ollama/utils.ts index 16bcb277f3c..ebcb54c73c4 100644 --- a/lib/shared/src/llm-providers/ollama/utils.ts +++ b/lib/shared/src/llm-providers/ollama/utils.ts @@ -17,8 +17,7 @@ export async function fetchLocalOllamaModels(): Promise { output: CHAT_OUTPUT_TOKEN_BUDGET, }, undefined, - undefined, - [ModelTag.Ollama, ModelTag.Local] + [ModelTag.Ollama, ModelTag.Experimental] ) ) } diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index eb67eafc26f..6399f30d5aa 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -8,7 +8,6 @@ import { import { ModelTag } from './tags' import { type ModelContextWindow, ModelUsage } from './types' -import { ModelUIGroup } from './utils' const basicContextWindow: ModelContextWindow = { input: CHAT_INPUT_TOKEN_BUDGET, @@ -38,35 +37,29 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'anthropic/claude-3-sonnet-20240229', provider: 'Anthropic', default: true, - codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - uiGroup: ModelUIGroup.Balanced, - tags: [ModelTag.Free, ModelTag.Balanced], + tags: [ModelTag.Gateway, ModelTag.Balanced], }, { title: 'Claude 3.5 Sonnet', model: 'anthropic/claude-3-5-sonnet-20240620', provider: 'Anthropic', default: false, - codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - uiGroup: ModelUIGroup.Accuracy, - tags: [ModelTag.Free, ModelTag.Recommended, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Recommended, ModelTag.Accuracy], }, { title: 'Claude 3 Opus', model: 'anthropic/claude-3-opus-20240229', provider: 'Anthropic', default: false, - codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - uiGroup: ModelUIGroup.Accuracy, tags: [ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], }, { @@ -74,11 +67,9 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'anthropic/claude-3-haiku-20240307', provider: 'Anthropic', default: false, - codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - uiGroup: ModelUIGroup.Speed, - tags: [ModelTag.Free, ModelTag.Speed], + tags: [ModelTag.Gateway, ModelTag.Speed], }, // -------------------------------- @@ -89,11 +80,9 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'openai/gpt-4o', provider: 'OpenAI', default: false, - codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - uiGroup: ModelUIGroup.Accuracy, tags: [ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], }, { @@ -101,10 +90,8 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'openai/gpt-4-turbo', provider: 'OpenAI', default: false, - codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - uiGroup: ModelUIGroup.Balanced, tags: [ModelTag.Pro, ModelTag.Accuracy], }, { @@ -112,11 +99,9 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'openai/gpt-3.5-turbo', provider: 'OpenAI', default: false, - codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - uiGroup: ModelUIGroup.Speed, - tags: [ModelTag.Free, ModelTag.Speed], + tags: [ModelTag.Gateway, ModelTag.Speed], }, // -------------------------------- @@ -127,22 +112,18 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'google/gemini-1.5-pro-latest', provider: 'Google', default: false, - codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, - uiGroup: ModelUIGroup.Accuracy, - tags: [ModelTag.Free, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Accuracy], }, { title: 'Gemini 1.5 Flash', model: 'google/gemini-1.5-flash-latest', provider: 'Google', default: false, - codyProOnly: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, - uiGroup: ModelUIGroup.Speed, - tags: [ModelTag.Free, ModelTag.Speed], + tags: [ModelTag.Gateway, ModelTag.Speed], }, // TODO (tom) Improve prompt for Mixtral + Edit to see if we can use it there too. @@ -151,22 +132,18 @@ export const DEFAULT_DOT_COM_MODELS = [ model: 'fireworks/accounts/fireworks/models/mixtral-8x7b-instruct', provider: 'Mistral', default: false, - codyProOnly: false, usage: [ModelUsage.Chat], contextWindow: basicContextWindow, - uiGroup: ModelUIGroup.Speed, - tags: [ModelTag.Free, ModelTag.Speed], + tags: [ModelTag.Gateway, ModelTag.Speed], }, { title: 'Mixtral 8x22B', model: 'fireworks/accounts/fireworks/models/mixtral-8x22b-instruct', provider: 'Mistral', default: false, - codyProOnly: false, usage: [ModelUsage.Chat], contextWindow: basicContextWindow, - uiGroup: ModelUIGroup.Accuracy, - tags: [ModelTag.Free, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Accuracy], }, ] as const satisfies Model[] diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 02e6401c59a..b3e47ed139e 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -2,7 +2,7 @@ import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' import type { ModelTag } from './tags' import type { ModelContextWindow, ModelUsage } from './types' -import { getModelInfo } from './utils' +import { getModelInfo, isCodyProModel } from './utils' /** * Model describes an LLM model and its capabilities. @@ -14,8 +14,6 @@ export class Model { */ public default = false - // Whether the model is only available to Pro users - public codyProOnly = false // The name of the provider of the model, e.g. "Anthropic" public provider: string // The title of the model, e.g. "Claude 3 Sonnet" @@ -55,7 +53,6 @@ export class Model { */ apiEndpoint?: string }, - public readonly uiGroup?: string, /** * The tags assigned for categorizing the model. */ @@ -137,7 +134,7 @@ export class ModelsService { const currentDefault = currentModel ? availableModels.find(m => m.model === currentModel) : undefined - const canUseCurrentDefault = currentDefault?.codyProOnly ? isCodyProUser : !!currentDefault + const canUseCurrentDefault = isCodyProModel(currentDefault) ? isCodyProUser : !!currentDefault return ModelsService.models .filter(m => m.usage.includes(type)) diff --git a/lib/shared/src/models/tags.ts b/lib/shared/src/models/tags.ts index ba30816ef7c..dc3de80357e 100644 --- a/lib/shared/src/models/tags.ts +++ b/lib/shared/src/models/tags.ts @@ -1,21 +1,20 @@ export enum ModelTag { + // UI Groups Accuracy = 'accuracy', Speed = 'speed', Balanced = 'balanced', - Recommended = 'recommended', Deprecated = 'deprecated', - - Dev = 'dev', - New = 'new', Experimental = 'experimental', - Preview = 'preview', + // Tiers Pro = 'pro', Free = 'free', Enterprise = 'enterprise', - Local = 'local', - BYOK = 'byok', + // Host / Model Type + Gateway = 'cody-gateway', + BYOK = 'byok', Ollama = 'ollama', + Dev = 'dev', } diff --git a/lib/shared/src/models/utils.ts b/lib/shared/src/models/utils.ts index 98e85bfa8a9..76f5af37154 100644 --- a/lib/shared/src/models/utils.ts +++ b/lib/shared/src/models/utils.ts @@ -1,3 +1,6 @@ +import type { Model } from '.' +import { ModelTag } from './tags' + export function getProviderName(name: string): string { const providerName = name.toLowerCase() switch (providerName) { @@ -27,12 +30,6 @@ export function getModelInfo(modelID: string): { return { provider, title } } -/** Common {@link ModelsService.uiGroup} values. */ -export const ModelUIGroup: Record = { - Accuracy: 'Optimized for Accuracy', - Balanced: 'Balanced (Speed & Accuracy)', - Speed: 'Optimized for Speed', - Ollama: 'Ollama (Local)', - // Used for identifying the model type but currently not used for displaying in the UI. - Enterprise: 'Enterprise', +export function isCodyProModel(model?: Model): boolean { + return Boolean(model?.tags.includes(ModelTag.Pro)) } diff --git a/vscode/src/edit/input/get-items/model.ts b/vscode/src/edit/input/get-items/model.ts index c2910f29b0c..a0e2c9e60ae 100644 --- a/vscode/src/edit/input/get-items/model.ts +++ b/vscode/src/edit/input/get-items/model.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode' import { type EditModel, type Model, isDefined } from '@sourcegraph/cody-shared' +import { isCodyProModel } from '@sourcegraph/cody-shared/src/models/utils' import { QUICK_PICK_ITEM_CHECKED_PREFIX, QUICK_PICK_ITEM_EMPTY_INDENT_PREFIX, @@ -35,7 +36,7 @@ export const getModelOptionItems = (modelOptions: Model[], isCodyPro: boolean): alwaysShow: true, model: modelOption.model, modelTitle: modelOption.title, - codyProOnly: modelOption.codyProOnly, + codyProOnly: isCodyProModel(modelOption), } }) .filter(isDefined) diff --git a/vscode/src/models/modelMigrator.ts b/vscode/src/models/modelMigrator.ts index c6a3962371b..f8703ab0fdf 100644 --- a/vscode/src/models/modelMigrator.ts +++ b/vscode/src/models/modelMigrator.ts @@ -9,7 +9,6 @@ const DEPRECATED_DOT_COM_MODELS = [ model: 'anthropic/claude-2.0', provider: 'Anthropic', default: false, - codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: { input: 0, output: 0 }, }, @@ -18,7 +17,6 @@ const DEPRECATED_DOT_COM_MODELS = [ model: 'anthropic/claude-2.1', provider: 'Anthropic', default: false, - codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: { input: 0, output: 0 }, }, @@ -27,7 +25,6 @@ const DEPRECATED_DOT_COM_MODELS = [ model: 'anthropic/claude-instant-1.2', provider: 'Anthropic', default: false, - codyProOnly: true, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: { input: 0, output: 0 }, }, diff --git a/vscode/src/models/sync.test.ts b/vscode/src/models/sync.test.ts index 7b541af9827..4f75cdcb888 100644 --- a/vscode/src/models/sync.test.ts +++ b/vscode/src/models/sync.test.ts @@ -1,6 +1,6 @@ import { Model, - ModelUIGroup, + ModelTag, ModelUsage, ModelsService, RestClient, @@ -68,7 +68,7 @@ describe('syncModels', () => { [ModelUsage.Chat, ModelUsage.Edit], getEnterpriseContextWindow(chatModel, authStatus.configOverwrites), undefined, - ModelUIGroup.Enterprise + [ModelTag.Enterprise] ), ]) }) diff --git a/vscode/src/models/sync.ts b/vscode/src/models/sync.ts index bcb1622cc8c..8648a75811c 100644 --- a/vscode/src/models/sync.ts +++ b/vscode/src/models/sync.ts @@ -3,7 +3,6 @@ import { type AuthStatus, CHAT_INPUT_TOKEN_BUDGET, Model, - ModelUIGroup, ModelUsage, ModelsService, RestClient, @@ -75,7 +74,6 @@ export async function syncModels(authStatus: AuthStatus): Promise { authStatus?.configOverwrites ), undefined, - ModelUIGroup.Enterprise, [ModelTag.Enterprise] ), ]) @@ -119,7 +117,6 @@ export function registerModelsFromVSCodeConfiguration() { [ModelUsage.Chat, ModelUsage.Edit], { input: m.inputTokens ?? CHAT_INPUT_TOKEN_BUDGET, output: m.outputTokens ?? ANSWER_TOKENS }, { apiKey: m.apiKey, apiEndpoint: m.apiEndpoint }, - undefined, [ModelTag.Dev, ModelTag.Experimental] ) models.push(provider) diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx index fa11dcf0300..593743c7cc7 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx @@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react' import { VSCodeStandaloneComponent } from '../../storybook/VSCodeStoryDecorator' -import { type Model, ModelUIGroup, ModelUsage, getDotComDefaultModels } from '@sourcegraph/cody-shared' +import { type Model, ModelUsage, getDotComDefaultModels } from '@sourcegraph/cody-shared' import { ModelTag } from '@sourcegraph/cody-shared/src/models/tags' import { useArgs } from '@storybook/preview-api' import { ModelSelectField } from './ModelSelectField' @@ -13,12 +13,10 @@ const MODELS: Model[] = [ title: 'Llama 3 q4_K f16', provider: 'Ollama', model: 'ollama/llama-3', - codyProOnly: false, contextWindow: { input: 100, output: 100 }, default: false, usage: [ModelUsage.Chat], - uiGroup: ModelUIGroup.Ollama, - tags: [ModelTag.Ollama, ModelTag.Local, ModelTag.Dev], + tags: [ModelTag.Ollama, ModelTag.Dev], }, ] diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx index a285c49bdcb..cbbb501381d 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx @@ -1,4 +1,5 @@ -import { type Model, ModelUIGroup } from '@sourcegraph/cody-shared' +import { type Model, ModelTag } from '@sourcegraph/cody-shared' +import { isCodyProModel } from '@sourcegraph/cody-shared/src/models/utils' import { clsx } from 'clsx' import { BookOpenIcon, BuildingIcon, ExternalLinkIcon } from 'lucide-react' import { type FunctionComponent, type ReactNode, useCallback, useMemo } from 'react' @@ -53,7 +54,7 @@ export const ModelSelectField: React.FunctionComponent<{ (model: Model): void => { telemetryRecorder.recordEvent('cody.modelSelector', 'select', { metadata: { - modelIsCodyProOnly: model.codyProOnly ? 1 : 0, + modelIsCodyProOnly: model ? 1 : 0, isCodyProUser: isCodyProUser ? 1 : 0, }, privateMetadata: { @@ -63,7 +64,7 @@ export const ModelSelectField: React.FunctionComponent<{ }, }) - if (showCodyProBadge && model.codyProOnly) { + if (showCodyProBadge && isCodyProModel(model)) { getVSCodeAPI().postMessage({ command: 'links', value: 'https://sourcegraph.com/cody/subscription', @@ -125,7 +126,7 @@ export const ModelSelectField: React.FunctionComponent<{ // needs-cody-pro models should be clickable (not disabled) so the user can // be taken to the upgrade page. disabled: !['available', 'needs-cody-pro'].includes(availability), - group: m.uiGroup ?? 'Other', + group: getModelDropDownUIGroup(m), tooltip: availability === 'not-selectable-on-enterprise' ? 'Chat model set by your Sourcegraph Enterprise admin' @@ -137,31 +138,7 @@ export const ModelSelectField: React.FunctionComponent<{ [models, userInfo] ) const optionsByGroup: { group: string; options: SelectListOption[] }[] = useMemo(() => { - const groups = new Map() - for (const option of options) { - const groupOptions = groups.get(option.group ?? '') - if (groupOptions) { - groupOptions.push(option) - } else { - groups.set(option.group ?? '', [option]) - } - } - return Array.from(groups.entries()) - .sort((a, b) => { - const aIndex = GROUP_ORDER.indexOf(a[0]) - const bIndex = GROUP_ORDER.indexOf(b[0]) - if (aIndex !== -1 && bIndex !== -1) { - return aIndex - bIndex - } - if (aIndex !== -1) { - return -1 - } - if (bIndex !== -1) { - return 1 - } - return 0 - }) - .map(([group, options]) => ({ group, options })) + return optionByGroup(options) }, [options]) const onChange = useCallback( @@ -286,13 +263,6 @@ export const ModelSelectField: React.FunctionComponent<{ const ENTERPRISE_MODEL_DOCS_PAGE = 'https://sourcegraph.com/docs/cody/clients/enable-cody-enterprise?utm_source=cody.modelSelector' -const GROUP_ORDER = [ - ModelUIGroup.Accuracy, - ModelUIGroup.Balanced, - ModelUIGroup.Speed, - ModelUIGroup.Ollama, -] - type ModelAvailability = 'available' | 'needs-cody-pro' | 'not-selectable-on-enterprise' function modelAvailability( @@ -302,7 +272,7 @@ function modelAvailability( if (!userInfo.isDotComUser) { return 'not-selectable-on-enterprise' } - if (model.codyProOnly && !userInfo.isCodyProUser) { + if (isCodyProModel(model) && !userInfo.isCodyProUser) { return 'needs-cody-pro' } return 'available' @@ -324,12 +294,10 @@ const ModelTitleWithIcon: FunctionComponent<{ {modelAvailability === 'needs-cody-pro' && ( Cody Pro )} - {model.provider === 'Ollama' && Experimental} - {model.title === 'Claude 3 Sonnet' || - ((model.title === 'Claude 3 Opus' || - model.title === 'GPT-4o' || - model.title === 'Claude 3.5 Sonnet') && - modelAvailability !== 'needs-cody-pro') ? ( + {model.tags.includes(ModelTag.Experimental) && ( + Experimental + )} + {model.tags.includes(ModelTag.Recommended) && modelAvailability !== 'needs-cody-pro' ? ( Recommended @@ -344,3 +312,44 @@ const ChatModelIcon: FunctionComponent<{ model: string; className?: string }> = const ModelIcon = chatModelIconComponent(model) return ModelIcon ? : null } + +/** Common {@link ModelsService.uiGroup} values. */ +export const ModelUIGroup: Record = { + Accuracy: 'Optimized for Accuracy', + Balanced: 'Balanced (Speed & Accuracy)', + Speed: 'Optimized for Speed', + Ollama: 'Ollama (Local)', + Other: 'Other', +} + +const getModelDropDownUIGroup = (model: Model): string => { + if (model.tags.includes(ModelTag.Accuracy)) return ModelUIGroup.Accuracy + if (model.tags.includes(ModelTag.Balanced)) return ModelUIGroup.Balanced + if (model.tags.includes(ModelTag.Speed)) return ModelUIGroup.Speed + if (model.tags.includes(ModelTag.Ollama)) return ModelUIGroup.Ollama + return ModelUIGroup.Other +} + +const optionByGroup = ( + options: SelectListOption[] +): { group: string; options: SelectListOption[] }[] => { + const groupOrder = [ + ModelUIGroup.Accuracy, + ModelUIGroup.Balanced, + ModelUIGroup.Speed, + ModelUIGroup.Ollama, + ModelUIGroup.Other, + ] + const groups = new Map() + + for (const option of options) { + const group = option.group ?? ModelUIGroup.Other + const groupOptions = groups.get(group) ?? [] + groupOptions.push(option) + groups.set(group, groupOptions) + } + + return [...groups.entries()] + .sort(([a], [b]) => groupOrder.indexOf(a) - groupOrder.indexOf(b)) + .map(([group, options]) => ({ group, options })) +} From e412283cf7f6fd22248bb67bdd7bad751a5cf64d Mon Sep 17 00:00:00 2001 From: Beatrix Date: Wed, 3 Jul 2024 13:46:09 -0700 Subject: [PATCH 04/34] Update bindings --- .../kotlin/com/sourcegraph/cody/protocol_generated/Model.kt | 2 -- .../kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt index c7df2339c8e..a75a2b6d5dd 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt @@ -3,9 +3,7 @@ package com.sourcegraph.cody.protocol_generated; data class Model( val default: Boolean, - val codyProOnly: Boolean, val provider: String, val title: String, - val deprecated: Boolean, ) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt index 64888c8609d..6d69602bf0e 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt @@ -7,6 +7,8 @@ data class Uri( val path: String, val query: String, val fragment: String, - val fsPath: String, +) + +al fsPath: String, ) From a7c02d5051244eaad3cc06ed492cecf1ae08977f Mon Sep 17 00:00:00 2001 From: Beatrix Date: Wed, 3 Jul 2024 13:52:59 -0700 Subject: [PATCH 05/34] Update bindings --- .../kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt | 4 +--- lib/shared/src/models/dotcom.ts | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt index 6d69602bf0e..64888c8609d 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Uri.kt @@ -7,8 +7,6 @@ data class Uri( val path: String, val query: String, val fragment: String, -) - -al fsPath: String, + val fsPath: String, ) diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 6399f30d5aa..3b9adc140b5 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -60,7 +60,7 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - tags: [ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], }, { title: 'Claude 3 Haiku', @@ -83,7 +83,7 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - tags: [ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Pro, ModelTag.Recommended, ModelTag.Accuracy], }, { title: 'GPT-4 Turbo', @@ -92,7 +92,7 @@ export const DEFAULT_DOT_COM_MODELS = [ default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - tags: [ModelTag.Pro, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Pro, ModelTag.Accuracy], }, { title: 'GPT-3.5 Turbo', From ee4ba56b63a25c1b494c2798b37c1992a1d5b7f5 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Wed, 3 Jul 2024 23:13:48 -0700 Subject: [PATCH 06/34] removed getModel and setModel --- agent/src/agent.ts | 29 +- lib/shared/src/auth/types.ts | 12 + lib/shared/src/llm-providers/ollama/utils.ts | 13 +- lib/shared/src/llm-providers/utils.ts | 2 +- lib/shared/src/models/dotcom.ts | 11 - lib/shared/src/models/index.test.ts | 26 +- lib/shared/src/models/index.ts | 301 +++++++++++++----- .../src/chat/chat-view/ChatPanelsManager.ts | 3 +- vscode/src/chat/chat-view/SimpleChatModel.ts | 6 +- .../chat/chat-view/SimpleChatPanelProvider.ts | 17 +- vscode/src/chat/chat-view/prompt.test.ts | 18 +- vscode/src/commands/scm/source-control.ts | 2 +- vscode/src/edit/input/get-input.ts | 4 +- vscode/src/edit/manager.ts | 14 +- vscode/src/edit/utils/edit-models.ts | 2 +- vscode/src/main.ts | 4 +- vscode/src/models/index.ts | 61 ---- vscode/src/models/modelMigrator.ts | 3 - vscode/src/models/sync.test.ts | 18 +- vscode/src/models/sync.ts | 39 +-- vscode/webviews/App.tsx | 3 +- vscode/webviews/Chat.tsx | 2 +- .../human/editor/toolbar/Toolbar.tsx | 2 +- vscode/webviews/chat/fixtures.ts | 2 +- .../webviews/chat/models/chatModelContext.tsx | 2 +- .../ModelSelectField.story.tsx | 13 +- .../modelSelectField/ModelSelectField.tsx | 10 +- web/lib/components/CodyWebChat.tsx | 1 + 28 files changed, 345 insertions(+), 275 deletions(-) delete mode 100644 vscode/src/models/index.ts diff --git a/agent/src/agent.ts b/agent/src/agent.ts index 9af33dd1738..26f421c0818 100644 --- a/agent/src/agent.ts +++ b/agent/src/agent.ts @@ -2,12 +2,7 @@ import { spawn } from 'node:child_process' import path from 'node:path' import type { Polly, Request } from '@pollyjs/core' -import { - type CodyCommand, - getDotComDefaultModels, - isWindows, - telemetryRecorder, -} from '@sourcegraph/cody-shared' +import { type CodyCommand, isWindows, telemetryRecorder } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { StreamMessageReader, StreamMessageWriter, createMessageConnection } from 'vscode-jsonrpc/node' @@ -43,7 +38,6 @@ import type { Har } from '@pollyjs/persister' import levenshtein from 'js-levenshtein' import * as uuid from 'uuid' import type { MessageConnection } from 'vscode-jsonrpc' -import { ModelUsage } from '../../lib/shared/src/models/types' import type { CommandResult } from '../../vscode/src/CommandResult' import { loadTscRetriever } from '../../vscode/src/completions/context/retrievers/tsc/load-tsc-retriever' import { supportedTscLanguages } from '../../vscode/src/completions/context/retrievers/tsc/supportedTscLanguages' @@ -1079,17 +1073,11 @@ export class Agent extends MessageHandler implements ExtensionClient { this.registerAuthenticatedRequest('chat/restore', async ({ modelID, messages, chatID }) => { const authStatus = await vscode.commands.executeCommand('cody.auth.status') - let theModel = modelID - ? modelID - : ModelsService.getModels( - ModelUsage.Chat, - authStatus.isDotCom && !authStatus.userCanUpgrade - ).at(0)?.model - if (!theModel) { - theModel = getDotComDefaultModels()[0].model - } - const chatModel = new SimpleChatModel(modelID!, [], chatID) + const chatModel = new SimpleChatModel( + modelID || ModelsService.getDefaultChatModel(authStatus), + chatID + ) for (const message of messages) { const deserializedMessage = PromptString.unsafe_deserializeChatMessage(message) if (deserializedMessage.error) { @@ -1111,10 +1099,7 @@ export class Agent extends MessageHandler implements ExtensionClient { this.registerAuthenticatedRequest('chat/models', async ({ modelUsage }) => { const authStatus = await vscode.commands.executeCommand('cody.auth.status') - const providers = ModelsService.getModels( - modelUsage, - authStatus.isDotCom && !authStatus.userCanUpgrade - ) + const providers = ModelsService.getModels(modelUsage, authStatus) return { models: providers ?? [] } }) @@ -1129,7 +1114,7 @@ export class Agent extends MessageHandler implements ExtensionClient { // Return filtered (non-empty) chats by default, but if requests has fullHistory: true // return the full list of chats from the storage, empty chats included .filter( - ([chatID, chatTranscript]) => + ([_, chatTranscript]) => chatTranscript.interactions.length > 0 || fullHistory ) .map(([chatID, chatTranscript]) => ({ diff --git a/lib/shared/src/auth/types.ts b/lib/shared/src/auth/types.ts index 8faea24788f..a97c36c9798 100644 --- a/lib/shared/src/auth/types.ts +++ b/lib/shared/src/auth/types.ts @@ -118,3 +118,15 @@ export const offlineModeAuthStatus = { avatarURL: '', codyApiVersion: 0, } satisfies AuthStatus + +export function isCodyProUser(authStatus: AuthStatus): boolean { + return authStatus.isDotCom && !authStatus.userCanUpgrade +} + +export function isFreeUser(authStatus: AuthStatus): boolean { + return authStatus.isDotCom && authStatus.userCanUpgrade +} + +export function isEnterpriseUser(authStatus: AuthStatus): boolean { + return !authStatus.isDotCom +} diff --git a/lib/shared/src/llm-providers/ollama/utils.ts b/lib/shared/src/llm-providers/ollama/utils.ts index ebcb54c73c4..fe9b1b9ac09 100644 --- a/lib/shared/src/llm-providers/ollama/utils.ts +++ b/lib/shared/src/llm-providers/ollama/utils.ts @@ -9,15 +9,14 @@ import { CHAT_OUTPUT_TOKEN_BUDGET } from '../../token/constants' export async function fetchLocalOllamaModels(): Promise { return (await ollama.list()).models?.map( m => - new Model( - `ollama/${m.name}`, - [ModelUsage.Chat, ModelUsage.Edit], - { + new Model({ + model: `ollama/${m.name}`, + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: { input: OLLAMA_DEFAULT_CONTEXT_WINDOW, output: CHAT_OUTPUT_TOKEN_BUDGET, }, - undefined, - [ModelTag.Ollama, ModelTag.Experimental] - ) + tags: [ModelTag.Ollama, ModelTag.Experimental], + }) ) } diff --git a/lib/shared/src/llm-providers/utils.ts b/lib/shared/src/llm-providers/utils.ts index ea29d0ed19e..717288a9356 100644 --- a/lib/shared/src/llm-providers/utils.ts +++ b/lib/shared/src/llm-providers/utils.ts @@ -9,7 +9,7 @@ export function getCompletionsModelConfig(modelID: string): CompletionsModelConf const { model, - config: { apiKey = '', apiEndpoint } = {}, + clientSideConfig: { apiKey = '', apiEndpoint } = {}, } = provider const strippedModelName = model.split('/').pop() || model diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 3b9adc140b5..4bacd5a53a4 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -36,7 +36,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Claude 3 Sonnet', model: 'anthropic/claude-3-sonnet-20240229', provider: 'Anthropic', - default: true, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, @@ -46,7 +45,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Claude 3.5 Sonnet', model: 'anthropic/claude-3-5-sonnet-20240620', provider: 'Anthropic', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, @@ -56,7 +54,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Claude 3 Opus', model: 'anthropic/claude-3-opus-20240229', provider: 'Anthropic', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, @@ -66,7 +63,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Claude 3 Haiku', model: 'anthropic/claude-3-haiku-20240307', provider: 'Anthropic', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, tags: [ModelTag.Gateway, ModelTag.Speed], @@ -79,7 +75,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'GPT-4o', model: 'openai/gpt-4o', provider: 'OpenAI', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, @@ -89,7 +84,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'GPT-4 Turbo', model: 'openai/gpt-4-turbo', provider: 'OpenAI', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, tags: [ModelTag.Gateway, ModelTag.Pro, ModelTag.Accuracy], @@ -98,7 +92,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'GPT-3.5 Turbo', model: 'openai/gpt-3.5-turbo', provider: 'OpenAI', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, tags: [ModelTag.Gateway, ModelTag.Speed], @@ -111,7 +104,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Gemini 1.5 Pro', model: 'google/gemini-1.5-pro-latest', provider: 'Google', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, tags: [ModelTag.Gateway, ModelTag.Accuracy], @@ -120,7 +112,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Gemini 1.5 Flash', model: 'google/gemini-1.5-flash-latest', provider: 'Google', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, tags: [ModelTag.Gateway, ModelTag.Speed], @@ -131,7 +122,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Mixtral 8x7B', model: 'fireworks/accounts/fireworks/models/mixtral-8x7b-instruct', provider: 'Mistral', - default: false, usage: [ModelUsage.Chat], contextWindow: basicContextWindow, tags: [ModelTag.Gateway, ModelTag.Speed], @@ -140,7 +130,6 @@ export const DEFAULT_DOT_COM_MODELS = [ title: 'Mixtral 8x22B', model: 'fireworks/accounts/fireworks/models/mixtral-8x22b-instruct', provider: 'Mistral', - default: false, usage: [ModelUsage.Chat], contextWindow: basicContextWindow, tags: [ModelTag.Gateway, ModelTag.Accuracy], diff --git a/lib/shared/src/models/index.test.ts b/lib/shared/src/models/index.test.ts index a141e8f8f54..36ad181caaa 100644 --- a/lib/shared/src/models/index.test.ts +++ b/lib/shared/src/models/index.test.ts @@ -1,16 +1,11 @@ -import { beforeAll, describe, expect, it } from 'vitest' +import { describe, expect, it } from 'vitest' import { Model, ModelsService } from '../models/index' -import { DOTCOM_URL } from '../sourcegraph-api/environments' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' import { getDotComDefaultModels } from './dotcom' import { ModelUsage } from './types' describe('Model Provider', () => { describe('getContextWindowByID', () => { - beforeAll(() => { - ModelsService.getModels(ModelUsage.Chat, false, DOTCOM_URL.toString()) - }) - it('returns default token limit for unknown model', () => { const max = ModelsService.getContextWindowByID('unknown-model') expect(max).toEqual({ input: CHAT_INPUT_TOKEN_BUDGET, output: CHAT_OUTPUT_TOKEN_BUDGET }) @@ -36,14 +31,17 @@ describe('Model Provider', () => { }) it('returns default token limit for unknown model - Enterprise user', () => { - ModelsService.getModels(ModelUsage.Chat, false, 'https://example.com') const cw = ModelsService.getContextWindowByID('unknown-model') expect(cw).toEqual({ input: CHAT_INPUT_TOKEN_BUDGET, output: CHAT_OUTPUT_TOKEN_BUDGET }) }) it('returns max token limit for known model - Enterprise user', () => { ModelsService.setModels([ - new Model('enterprise-model', [ModelUsage.Chat], { input: 200, output: 100 }), + new Model({ + model: 'enterprise-model', + usage: [ModelUsage.Chat], + contextWindow: { input: 200, output: 100 }, + }), ]) const cw = ModelsService.getContextWindowByID('enterprise-model') expect(cw.input).toEqual(200) @@ -51,10 +49,6 @@ describe('Model Provider', () => { }) describe('getMaxOutputCharsByModel', () => { - beforeAll(() => { - ModelsService.getModels(ModelUsage.Chat, false, DOTCOM_URL.toString()) - }) - it('returns default token limit for unknown model', () => { const { output } = ModelsService.getContextWindowByID('unknown-model') expect(output).toEqual(CHAT_OUTPUT_TOKEN_BUDGET) @@ -67,15 +61,17 @@ describe('Model Provider', () => { }) it('returns default token limit for unknown model - Enterprise user', () => { - ModelsService.getModels(ModelUsage.Chat, false, 'https://example.com') const { output } = ModelsService.getContextWindowByID('unknown-model') expect(output).toEqual(CHAT_OUTPUT_TOKEN_BUDGET) }) it('returns max token limit for known model - Enterprise user', () => { - ModelsService.getModels(ModelUsage.Chat, false, 'https://example.com') ModelsService.setModels([ - new Model('model-with-limit', [ModelUsage.Chat], { input: 8000, output: 2000 }), + new Model({ + model: 'model-with-limit', + usage: [ModelUsage.Chat], + contextWindow: { input: 8000, output: 2000 }, + }), ]) const { output } = ModelsService.getContextWindowByID('model-with-limit') expect(output).toEqual(2000) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index f3fbc578277..aa2c66e9316 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1,8 +1,9 @@ +import { type AuthStatus, isCodyProUser, isEnterpriseUser, isFreeUser } from '../auth/types' import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' -import type { ModelTag } from './tags' -import { type ModelContextWindow, ModelUsage } from './types' -import { getModelInfo, isCodyProModel } from './utils' +import { ModelTag } from './tags' +import { type ChatModel, type EditModel, type ModelContextWindow, ModelUsage } from './types' +import { getModelInfo } from './utils' export type ModelId = string export type ApiVersionId = string @@ -38,67 +39,71 @@ export interface ServerModel { * Model describes an LLM model and its capabilities. */ export class Model { + // public default = false /** - * Whether the model is the default model for new chats and edits. The user can change their - * default model. + * The model id that includes the provider name & the model name, + * e.g. "anthropic/claude-3-sonnet-20240229" + * + * TODO(PRIME-282): Replace this with a `ModelRef` instance and introduce a separate + * "modelId" that is distinct from the "modelName". (e.g. "claude-3-sonnet" vs. "claude-3-sonnet-20240229") */ - public default = false + public readonly model: string + /** + * The usage of the model, e.g. chat or edit. + */ + public readonly usage: ModelUsage[] + /** + * The default context window of the model reserved for Chat and Context. + * {@see TokenCounter on how the token usage is calculated.} + */ + public readonly contextWindow: ModelContextWindow - constructor( - /** - * The model id that includes the provider name & the model name, - * e.g. "anthropic/claude-3-sonnet-20240229" - * - * TODO(PRIME-282): Replace this with a `ModelRef` instance and introduce a separate - * "modelId" that is distinct from the "modelName". (e.g. "claude-3-sonnet" vs. "claude-3-sonnet-20240229") - */ - public readonly model: string, + /** + * The client-specific configuration for the model. + */ + public readonly clientSideConfig?: { /** - * The usage of the model, e.g. chat or edit. + * The API key for the model */ - public readonly usage: ModelUsage[], + apiKey?: string /** - * The default context window of the model reserved for Chat and Context. - * {@see TokenCounter on how the token usage is calculated.} + * The API endpoint for the model */ - public readonly contextWindow: ModelContextWindow = { + apiEndpoint?: string + } + + // The name of the provider of the model, e.g. "Anthropic" + public provider: string + // The title of the model, e.g. "Claude 3 Sonnet" + public readonly title: string + /** + * The tags assigned for categorizing the model. + */ + public readonly tags: ModelTag[] = [] + + constructor({ + model, + usage, + contextWindow = { input: CHAT_INPUT_TOKEN_BUDGET, output: CHAT_OUTPUT_TOKEN_BUDGET, }, - /** - * The client-specific configuration for the model. - */ - public readonly config?: { - /** - * The API key for the model - */ - apiKey?: string - /** - * The API endpoint for the model - */ - apiEndpoint?: string - }, - - public readonly tier?: 'free' | 'pro' | 'enterprise', + clientSideConfig, + tags = [], + provider, + title, + }: ModelParams) { + this.model = model + this.usage = usage + this.contextWindow = contextWindow + this.clientSideConfig = clientSideConfig + this.tags = tags - // The name of the provider of the model, e.g. "Anthropic" - public provider?: string, - // The title of the model, e.g. "Claude 3 Sonnet" - public readonly title?: string, - /** - * The tags assigned for categorizing the model. - */ - public readonly tags: ModelTag[] = [] - ) { - if (!provider || !title) { - const info = getModelInfo(model) - this.provider = provider ?? info.provider - this.title = title ?? info.title - } + const info = getModelInfo(model) + this.provider = provider ?? info.provider + this.title = title ?? info.title } - // HACK: Constructor override allowing you to supply the title directly, - // so it can be different. static fromApi({ modelRef, displayName, @@ -106,34 +111,79 @@ export class Model { category, tier, clientSideConfig, - contextWindow = { - maxInputTokens: CHAT_INPUT_TOKEN_BUDGET, - maxOutputTokens: CHAT_OUTPUT_TOKEN_BUDGET, - }, + contextWindow, }: ServerModel) { // BUG: There is data loss here and the potential for ambiguity. // BUG: We are assuming the modelRef is valid, but it might not be. const [providerId, _, modelId] = modelRef.split('::', 3) - return new Model( - modelId, - capabilities.flatMap(capabilityToUsage), - { + const categoryTag = ((): ModelTag => { + switch (category) { + case 'accuracy': + return ModelTag.Accuracy + case 'balanced': + return ModelTag.Balanced + case 'speed': + return ModelTag.Speed + } + })() + + const tierTag = ((): ModelTag => { + switch (tier) { + case 'free': + return ModelTag.Free + case 'pro': + return ModelTag.Pro + case 'enterprise': + return ModelTag.Enterprise + } + })() + + return new Model({ + model: modelId, + usage: capabilities.flatMap(capabilityToUsage), + contextWindow: { input: contextWindow.maxInputTokens, output: contextWindow.maxOutputTokens, }, // @ts-ignore - clientSideConfig, - category, - tier, - providerId, - displayName - ) + clientSideConfig: clientSideConfig, + tags: [categoryTag, tierTag], + provider: providerId, + title: displayName, + }) } } +interface ModelParams { + model: string + usage: ModelUsage[] + contextWindow?: ModelContextWindow + clientSideConfig?: { + apiKey?: string + apiEndpoint?: string + } + tags?: ModelTag[] + provider?: string + title?: string +} + export function isNewStyleEnterpriseModel(model: Model): boolean { - return model.tier === 'enterprise' + return model.tags.includes(ModelTag.Enterprise) +} + +export function getTier(model: Model): ModelTier { + if (model.tags.includes(ModelTag.Free)) { + return 'free' + } + if (model.tags.includes(ModelTag.Pro)) { + return 'pro' + } + if (model.tags.includes(ModelTag.Enterprise)) { + return 'enterprise' + } + + return 'pro' } /** @@ -169,6 +219,19 @@ export class ModelsService { */ private static localModels: Model[] = [] + private static defaultModels: Map = new Map() + + private static storage: Storage | undefined + + private static storageKeys = { + [ModelUsage.Chat]: 'chat', + [ModelUsage.Edit]: 'editModel', + } + + public static setStorage(storage: Storage): void { + ModelsService.storage = storage + } + public static async onConfigChange(): Promise { try { ModelsService.localModels = await fetchLocalOllamaModels() @@ -177,6 +240,10 @@ export class ModelsService { } } + private static getModelsByType(usage: ModelUsage): Model[] { + return ModelsService.models.filter(model => model.usage.includes(usage)) + } + /** * Sets the primary models available to the user. * NOTE: private instances can only support 1 provider ATM. @@ -197,24 +264,91 @@ export class ModelsService { } /** - * Get the list of the primary model, augmented with any local ones. - * If currentModel is provided, sets it as the default model. + * Gets the available models of the specified usage type, with the default model first. + * + * @param type - The usage type of the models to retrieve. + * @param authStatus - The authentication status of the user. + * @returns An array of models, with the default model first. */ - public static getModels(type: ModelUsage, isCodyProUser: boolean, currentModel?: string): Model[] { - const availableModels = ModelsService.models.filter(m => m.usage.includes(type)) + public static getModels(type: ModelUsage, authStatus: AuthStatus): Model[] { + const models = ModelsService.getModelsByType(type) + const currentModel = ModelsService.getDefaultModel(type, authStatus) + return [currentModel].concat(models.filter(m => m.model !== currentModel.model)) + } - const currentDefault = currentModel - ? availableModels.find(m => m.model === currentModel) - : undefined - const canUseCurrentDefault = isCodyProModel(currentDefault) ? isCodyProUser : !!currentDefault + public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model { + if (!authStatus.authenticated) { + throw new Error('You are not authenticated') + } + const current = ModelsService.defaultModels.get(type) + if (current) return current + + const models = ModelsService.getModelsByType(type) + + // Free users can only use the default model + if (isFreeUser(authStatus) || !ModelsService.storage) { + return models.find(m => ModelsService.canUserUseModel(authStatus, m)) || models[0] + } + + // Check for the last selected model + const lastSelectedModelID = ModelsService.storage.get(ModelsService.storageKeys[type]) + // TODO(jsm): Global migration should happen once in the activation + // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) + + // if (migratedModelID && migratedModelID !== lastSelectedModelID) { + // void setModel(migratedModelID, storageKey) + // } + + // return either the + // 1. last selected model + // 2. first model they can use + // 3. first model in the list + return ( + models.find(m => m.model === lastSelectedModelID) || + models.find(m => ModelsService.canUserUseModel(authStatus, m)) || + models[0] + ) + } - return ModelsService.models - .filter(m => m.usage.includes(type)) - ?.map(model => ({ - ...model, - // Set the current model as default - default: canUseCurrentDefault ? model.model === currentModel : model.default, - })) + public static getDefaultEditModel(authStatus: AuthStatus): EditModel { + return ModelsService.getDefaultModel(ModelUsage.Edit, authStatus).model + } + + public static getDefaultChatModel(authStatus: AuthStatus): ChatModel { + return ModelsService.getDefaultModel(ModelUsage.Chat, authStatus).model + } + + public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { + model = ModelsService.resolveModel(model) + ModelsService.defaultModels.set(type, model) + // If we have persistent storage set, write it there + await ModelsService.storage?.set(ModelsService.storageKeys[type], model.model) + } + + public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { + model = ModelsService.resolveModel(model) + const tier = getTier(model) + if (isEnterpriseUser(status)) { + return tier === 'enterprise' + } + if (isCodyProUser(status)) { + return tier !== 'enterprise' + } + if (isFreeUser(status)) { + return tier === 'free' + } + return false + } + + private static resolveModel(modelID: Model | string): Model { + if (typeof modelID !== 'string') { + return modelID + } + const model = ModelsService.models.find(m => m.model === modelID) + if (!model) { + throw new Error(`Unknown model: ${modelID}`) + } + return model } /** @@ -245,6 +379,11 @@ export class ModelsService { } } +interface Storage { + get(key: string): string | null + set(key: string, value: string): Promise +} + export function capabilityToUsage(capability: ModelCapability): ModelUsage[] { switch (capability) { case 'autocomplete': diff --git a/vscode/src/chat/chat-view/ChatPanelsManager.ts b/vscode/src/chat/chat-view/ChatPanelsManager.ts index 733de555aae..c0ad29e6293 100644 --- a/vscode/src/chat/chat-view/ChatPanelsManager.ts +++ b/vscode/src/chat/chat-view/ChatPanelsManager.ts @@ -225,8 +225,7 @@ export class ChatPanelsManager implements vscode.Disposable { private createProvider(): SimpleChatPanelProvider { const authStatus = this.options.authProvider.getAuthStatus() const isConsumer = authStatus.isDotCom - const isCodyProUser = !authStatus.userCanUpgrade - const models = ModelsService.getModels(ModelUsage.Chat, isCodyProUser) + const models = ModelsService.getModels(ModelUsage.Chat, authStatus) // Enterprise context is used for remote repositories context fetching // in vs cody extension it should be always off if extension is connected diff --git a/vscode/src/chat/chat-view/SimpleChatModel.ts b/vscode/src/chat/chat-view/SimpleChatModel.ts index 553acfd5f45..e183f5d2e8f 100644 --- a/vscode/src/chat/chat-view/SimpleChatModel.ts +++ b/vscode/src/chat/chat-view/SimpleChatModel.ts @@ -5,6 +5,7 @@ import { type ContextItem, type Message, type ModelContextWindow, + ModelUsage, ModelsService, type SerializedChatInteraction, type SerializedChatTranscript, @@ -21,17 +22,18 @@ export class SimpleChatModel { public contextWindow: ModelContextWindow constructor( public modelID: string, - private messages: ChatMessage[] = [], public readonly sessionID: string = new Date(Date.now()).toUTCString(), + private messages: ChatMessage[] = [], private customChatTitle?: string, private selectedRepos?: Repo[] ) { this.contextWindow = ModelsService.getContextWindowByID(this.modelID) } - public updateModel(newModelID: string): void { + public async updateModel(newModelID: string): Promise { this.modelID = newModelID this.contextWindow = ModelsService.getContextWindowByID(this.modelID) + await ModelsService.setDefaultModel(ModelUsage.Chat, newModelID) } public isEmpty(): boolean { diff --git a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts index b81a91196c7..05a976014df 100644 --- a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts +++ b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts @@ -2,6 +2,7 @@ import * as uuid from 'uuid' import * as vscode from 'vscode' import { + type AuthStatus, type BillingCategory, type BillingProduct, CHAT_INPUT_TOKEN_BUDGET, @@ -71,7 +72,6 @@ import type { LocalEmbeddingsController } from '../../local-context/local-embedd import { rewriteChatQuery } from '../../local-context/rewrite-chat-query' import type { SymfRunner } from '../../local-context/symf' import { logDebug } from '../../log' -import { chatModel } from '../../models' import { migrateAndNotifyForOutdatedModels } from '../../models/modelMigrator' import { gitCommitIdFromGitExtension } from '../../repository/git-extension-api' import type { AuthProvider } from '../../services/AuthProvider' @@ -202,7 +202,7 @@ export class SimpleChatPanelProvider this.remoteSearch = enterpriseContext?.createRemoteSearch() || null this.editor = editor - this.chatModel = new SimpleChatModel(getDefaultModelID(authProvider, models)) + this.chatModel = new SimpleChatModel(getDefaultModelID(authProvider.getAuthStatus())) this.guardrails = guardrails this.startTokenReceiver = startTokenReceiver @@ -878,7 +878,6 @@ export class SimpleChatPanelProvider private async handleSetChatModel(modelID: string): Promise { this.chatModel.updateModel(modelID) - await chatModel.set(modelID) } private async handleGetAllMentionProvidersMetadata(): Promise { @@ -1113,11 +1112,7 @@ export class SimpleChatPanelProvider if (!authStatus?.isLoggedIn) { return } - const models = ModelsService.getModels( - ModelUsage.Chat, - authStatus.isDotCom && !authStatus.userCanUpgrade, - this.chatModel.modelID - ) + const models = ModelsService.getModels(ModelUsage.Chat, authStatus) void this.postMessage({ type: 'chatModels', @@ -1604,6 +1599,7 @@ function newChatModelFromSerializedChatTranscript( ): SimpleChatModel { return new SimpleChatModel( migrateAndNotifyForOutdatedModels(json.chatModel || modelID)!, + json.id, json.interactions.flatMap((interaction: SerializedChatInteraction): ChatMessage[] => [ PromptString.unsafe_deserializeChatMessage(interaction.humanMessage), @@ -1612,7 +1608,6 @@ function newChatModelFromSerializedChatTranscript( : null, ].filter(isDefined) ), - json.id, json.chatTitle, json.enhancedContext?.selectedRepos ) @@ -1655,9 +1650,9 @@ export function revealWebviewViewOrPanel(viewOrPanel: vscode.WebviewView | vscod } } -function getDefaultModelID(authProvider: AuthProvider, models: Model[]): string { +function getDefaultModelID(status: AuthStatus): string { try { - return chatModel.get(authProvider, models) + return ModelsService.getDefaultChatModel(status) } catch { return '(pending)' } diff --git a/vscode/src/chat/chat-view/prompt.test.ts b/vscode/src/chat/chat-view/prompt.test.ts index 9ea923f0b73..664ef18420d 100644 --- a/vscode/src/chat/chat-view/prompt.test.ts +++ b/vscode/src/chat/chat-view/prompt.test.ts @@ -21,7 +21,11 @@ describe('DefaultPrompter', () => { it('constructs a prompt with no context', async () => { ModelsService.setModels([ - new Model('a-model-id', [ModelUsage.Chat], { input: 100000, output: 100 }), + new Model({ + model: 'a-model-id', + usage: [ModelUsage.Chat], + contextWindow: { input: 100000, output: 100 }, + }), ]) const chat = new SimpleChatModel('a-model-id') chat.addHumanMessage({ text: ps`Hello` }) @@ -56,7 +60,11 @@ describe('DefaultPrompter', () => { })) ModelsService.setModels([ - new Model('a-model-id', [ModelUsage.Chat], { input: 100000, output: 100 }), + new Model({ + model: 'a-model-id', + usage: [ModelUsage.Chat], + contextWindow: { input: 100000, output: 100 }, + }), ]) const chat = new SimpleChatModel('a-model-id') chat.addHumanMessage({ text: ps`Hello` }) @@ -83,7 +91,11 @@ describe('DefaultPrompter', () => { it('prefers latest enhanced context', async () => { ModelsService.setModels([ - new Model('a-model-id', [ModelUsage.Chat], { input: 100000, output: 100 }), + new Model({ + model: 'a-model-id', + usage: [ModelUsage.Chat], + contextWindow: { input: 100000, output: 100 }, + }), ]) const chat = new SimpleChatModel('a-model-id') chat.addHumanMessage({ text: ps`Hello, world!` }) diff --git a/vscode/src/commands/scm/source-control.ts b/vscode/src/commands/scm/source-control.ts index ec2df234619..8d39099d08f 100644 --- a/vscode/src/commands/scm/source-control.ts +++ b/vscode/src/commands/scm/source-control.ts @@ -232,7 +232,7 @@ export class CodySourceControl implements vscode.Disposable { } public syncAuthStatus(authStatus: AuthStatus): void { - const models = ModelsService.getModels(ModelUsage.Chat, !authStatus.userCanUpgrade) + const models = ModelsService.getModels(ModelUsage.Chat, authStatus) const preferredModel = models?.find(p => p.model.includes('claude-3-haiku')) this.model = preferredModel ?? models[0] } diff --git a/vscode/src/edit/input/get-input.ts b/vscode/src/edit/input/get-input.ts index cf730bd2d05..033d57bb5c2 100644 --- a/vscode/src/edit/input/get-input.ts +++ b/vscode/src/edit/input/get-input.ts @@ -3,6 +3,7 @@ import { type EditModel, type EventSource, FILE_CONTEXT_MENTION_PROVIDER, + ModelUsage, ModelsService, PromptString, SYMBOL_CONTEXT_MENTION_PROVIDER, @@ -17,7 +18,6 @@ import { GENERAL_HELP_LABEL, LARGE_FILE_WARNING_LABEL } from '../../chat/context import { ACCOUNT_UPGRADE_URL } from '../../chat/protocol' import { executeDocCommand, executeTestEditCommand } from '../../commands/execute' import { getEditor } from '../../editor/active-editor' -import { editModel } from '../../models' import { type TextChange, updateRangeMultipleChanges } from '../../non-stop/tracked-range' import type { AuthProvider } from '../../services/AuthProvider' // biome-ignore lint/nursery/noRestrictedImports: Deprecated v1 telemetry used temporarily to support existing analytics. @@ -207,7 +207,7 @@ export const getInput = async ( return } - editModel.set(acceptedItem.model) + ModelsService.setDefaultModel(ModelUsage.Edit, acceptedItem.model) activeModelItem = acceptedItem activeModel = acceptedItem.model activeModelContextWindow = getContextWindowOnModelChange(acceptedItem.model) diff --git a/vscode/src/edit/manager.ts b/vscode/src/edit/manager.ts index 0ccab2c950d..2640fdf4bef 100644 --- a/vscode/src/edit/manager.ts +++ b/vscode/src/edit/manager.ts @@ -1,10 +1,9 @@ import * as vscode from 'vscode' import { - type AuthStatus, type ChatClient, ConfigFeaturesSingleton, - type Model, + ModelsService, telemetryRecorder, } from '@sourcegraph/cody-shared' @@ -18,7 +17,6 @@ import { DEFAULT_EVENT_SOURCE } from '@sourcegraph/cody-shared' import { isUriIgnoredByContextFilterWithNotification } from '../cody-ignore/context-filter' import { showCodyIgnoreNotification } from '../cody-ignore/notification' import type { ExtensionClient } from '../extension-client' -import { editModel } from '../models' import { ACTIVE_TASK_STATES } from '../non-stop/codelenses/constants' import type { AuthProvider } from '../services/AuthProvider' import { telemetryService } from '../services/telemetry' @@ -27,7 +25,6 @@ import type { ExecuteEditArguments } from './execute' import { EditProvider } from './provider' import { getEditIntent } from './utils/edit-intent' import { getEditMode } from './utils/edit-mode' -import { getEditModelsForUser } from './utils/edit-models' import { getEditLineSelection, getEditSmartSelection } from './utils/edit-selection' export interface EditManagerOptions { @@ -45,7 +42,6 @@ export class EditManager implements vscode.Disposable { private readonly controller: FixupController private disposables: vscode.Disposable[] = [] private editProviders = new WeakMap() - private models: Model[] = [] constructor(public options: EditManagerOptions) { this.controller = new FixupController(options.authProvider, options.extensionClient) @@ -77,10 +73,6 @@ export class EditManager implements vscode.Disposable { this.disposables.push(this.controller, editCommand, startCommand) } - public syncAuthStatus(authStatus: AuthStatus): void { - this.models = getEditModelsForUser(authStatus) - } - public async executeEdit(args: ExecuteEditArguments = {}): Promise { const { configuration = {}, @@ -124,7 +116,9 @@ export class EditManager implements vscode.Disposable { // Set default edit configuration, if not provided // It is possible that these values may be overriden later, e.g. if the user changes them in the edit input. const range = getEditLineSelection(document, proposedRange) - const model = configuration.model || editModel.get(this.options.authProvider, this.models) + const model = + configuration.model || + ModelsService.getDefaultEditModel(this.options.authProvider.getAuthStatus()) const intent = getEditIntent(document, range, configuration.intent) const mode = getEditMode(intent, configuration.mode) diff --git a/vscode/src/edit/utils/edit-models.ts b/vscode/src/edit/utils/edit-models.ts index a9714bae1b1..ba61d4cc468 100644 --- a/vscode/src/edit/utils/edit-models.ts +++ b/vscode/src/edit/utils/edit-models.ts @@ -8,7 +8,7 @@ import { import type { EditIntent } from '../types' export function getEditModelsForUser(authStatus: AuthStatus): Model[] { - return ModelsService.getModels(ModelUsage.Edit, !authStatus.userCanUpgrade) + return ModelsService.getModels(ModelUsage.Edit, authStatus) } export function getOverridenModelForIntent( diff --git a/vscode/src/main.ts b/vscode/src/main.ts index 3f6d644bea6..ca93e73175b 100644 --- a/vscode/src/main.ts +++ b/vscode/src/main.ts @@ -233,7 +233,7 @@ const register = async ( await localEmbeddings?.setAccessToken(config.serverEndpoint, config.accessToken) }, disposables) - const { chatManager, editorManager } = registerChat( + const { chatManager } = registerChat( { context, platform, @@ -260,7 +260,6 @@ const register = async ( // Chat Manager uses Simple Context Provider await chatManager.syncAuthStatus(authStatus) - editorManager.syncAuthStatus(authStatus) const parallelPromises: Promise[] = [] // feature flag provider @@ -318,7 +317,6 @@ const register = async ( const initAuthStatus = authProvider.getAuthStatus() await syncModels(initAuthStatus) await chatManager.syncAuthStatus(initAuthStatus) - editorManager.syncAuthStatus(initAuthStatus) await configWatcher.initAndOnChange(() => ModelsService.onConfigChange(), disposables) statusBar.syncAuthStatus(initAuthStatus) sourceControl.syncAuthStatus(initAuthStatus) diff --git a/vscode/src/models/index.ts b/vscode/src/models/index.ts deleted file mode 100644 index b18c3ce5439..00000000000 --- a/vscode/src/models/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { ChatModel, EditModel, Model } from '@sourcegraph/cody-shared' -import type { AuthProvider } from '../services/AuthProvider' -import { localStorage } from '../services/LocalStorageProvider' -import { migrateAndNotifyForOutdatedModels } from './modelMigrator' - -async function setModel(modelID: EditModel, storageKey: string) { - // Store the selected model in local storage to retrieve later - return localStorage.set(storageKey, modelID) -} - -function getModel(authProvider: AuthProvider, models: Model[], storageKey: string): T { - const authStatus = authProvider.getAuthStatus() - - if (!authStatus.authenticated) { - throw new Error('You are not authenticated') - } - - // Free user can only use the default model - if (authStatus.isDotCom && authStatus.userCanUpgrade) { - return models[0].model as T - } - - // Enterprise user can only use the default model - // We only support a single model for enterprise users right now - if (!authStatus.isDotCom) { - return models[0].model as T - } - - // Check for the last selected model - const lastSelectedModelID = localStorage.get(storageKey) - const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) - - if (migratedModelID && migratedModelID !== lastSelectedModelID) { - void setModel(migratedModelID, storageKey) - } - - if (migratedModelID) { - // If the last selected model exists in the list of models then we return it - const model = models.find(m => m.model === migratedModelID) - if (model) { - return migratedModelID as T - } - } - // If the user has not selected a model before then we return the default model - const defaultModel = models.find(m => m.default) || models[0] - if (!defaultModel) { - throw new Error('No chat model found in server-provided config') - } - return defaultModel.model as T -} - -function createModelAccessor(storageKey: string) { - return { - get: (authProvider: AuthProvider, models: Model[]) => - getModel(authProvider, models, storageKey), - set: (modelID: T) => setModel(modelID, storageKey), - } -} - -export const chatModel = createModelAccessor('model') -export const editModel = createModelAccessor('editModel') diff --git a/vscode/src/models/modelMigrator.ts b/vscode/src/models/modelMigrator.ts index f8703ab0fdf..f48188587da 100644 --- a/vscode/src/models/modelMigrator.ts +++ b/vscode/src/models/modelMigrator.ts @@ -8,7 +8,6 @@ const DEPRECATED_DOT_COM_MODELS = [ title: 'Claude 2.0', model: 'anthropic/claude-2.0', provider: 'Anthropic', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: { input: 0, output: 0 }, }, @@ -16,7 +15,6 @@ const DEPRECATED_DOT_COM_MODELS = [ title: 'Claude 2.1', model: 'anthropic/claude-2.1', provider: 'Anthropic', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: { input: 0, output: 0 }, }, @@ -24,7 +22,6 @@ const DEPRECATED_DOT_COM_MODELS = [ title: 'Claude Instant', model: 'anthropic/claude-instant-1.2', provider: 'Anthropic', - default: false, usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: { input: 0, output: 0 }, }, diff --git a/vscode/src/models/sync.test.ts b/vscode/src/models/sync.test.ts index 4f75cdcb888..86a0d5adf06 100644 --- a/vscode/src/models/sync.test.ts +++ b/vscode/src/models/sync.test.ts @@ -1,5 +1,4 @@ import { - Model, ModelTag, ModelUsage, ModelsService, @@ -8,7 +7,9 @@ import { getDotComDefaultModels, unauthenticatedStatus, } from '@sourcegraph/cody-shared' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { Model } from '@sourcegraph/cody-shared' +import { afterEach, beforeEach } from 'vitest' +import { describe, expect, it, vi } from 'vitest' import * as vscode from 'vscode' import { secretStorage } from '../services/SecretStorageProvider' import { syncModels } from './sync' @@ -63,13 +64,12 @@ describe('syncModels', () => { // i.e. this gets the one and only chat model from the Sourcegraph instance. expect(setModelsSpy).not.toHaveBeenCalledWith(getDotComDefaultModels()) expect(setModelsSpy).toHaveBeenCalledWith([ - new Model( - authStatus.configOverwrites.chatModel, - [ModelUsage.Chat, ModelUsage.Edit], - getEnterpriseContextWindow(chatModel, authStatus.configOverwrites), - undefined, - [ModelTag.Enterprise] - ), + new Model({ + model: authStatus.configOverwrites.chatModel, + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: getEnterpriseContextWindow(chatModel, authStatus.configOverwrites), + tags: [ModelTag.Enterprise], + }), ]) }) }) diff --git a/vscode/src/models/sync.ts b/vscode/src/models/sync.ts index 8648a75811c..ffeadf716ca 100644 --- a/vscode/src/models/sync.ts +++ b/vscode/src/models/sync.ts @@ -65,17 +65,16 @@ export async function syncModels(authStatus: AuthStatus): Promise { // automatically fallback to use the default model configured on the instance. if (authStatus?.configOverwrites?.chatModel) { ModelsService.setModels([ - new Model( - authStatus.configOverwrites.chatModel, + new Model({ + model: authStatus.configOverwrites.chatModel, // TODO (umpox) Add configOverwrites.editModel for separate edit support - [ModelUsage.Chat, ModelUsage.Edit], - getEnterpriseContextWindow( + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: getEnterpriseContextWindow( authStatus?.configOverwrites?.chatModel, authStatus?.configOverwrites ), - undefined, - [ModelTag.Enterprise] - ), + tags: [ModelTag.Enterprise], + }), ]) } else { // If the enterprise instance didn't have any configuration data for Cody, @@ -110,19 +109,21 @@ export function registerModelsFromVSCodeConfiguration() { return } - const models: Model[] = [] - for (const m of modelsConfig) { - const provider = new Model( - `${m.provider}/${m.model}`, - [ModelUsage.Chat, ModelUsage.Edit], - { input: m.inputTokens ?? CHAT_INPUT_TOKEN_BUDGET, output: m.outputTokens ?? ANSWER_TOKENS }, - { apiKey: m.apiKey, apiEndpoint: m.apiEndpoint }, - [ModelTag.Dev, ModelTag.Experimental] + ModelsService.addModels( + modelsConfig.map( + m => + new Model({ + model: `${m.provider}/${m.model}`, + usage: [ModelUsage.Chat, ModelUsage.Edit], + contextWindow: { + input: m.inputTokens ?? CHAT_INPUT_TOKEN_BUDGET, + output: m.outputTokens ?? ANSWER_TOKENS, + }, + clientSideConfig: { apiKey: m.apiKey, apiEndpoint: m.apiEndpoint }, + tags: [ModelTag.Dev, ModelTag.Experimental], + }) ) - models.push(provider) - } - - ModelsService.addModels(models) + ) } // Checks the local VS Code configuration and sees if the user has opted into fetching diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index d5b4ce8abdc..9a768bbce5d 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -10,6 +10,7 @@ import { type Model, PromptString, type SerializedChatTranscript, + isEnterpriseUser, } from '@sourcegraph/cody-shared' import type { UserAccountInfo } from './Chat' @@ -99,7 +100,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc // with E2E tests where change the DOTCOM_URL via the env variable TESTING_DOTCOM_URL. isDotComUser: message.authStatus.isDotCom, // Default to assuming they are a single model enterprise - isOldStyleEnterprise: !message.authStatus.isDotCom, + isOldStyleEnterpriseUser: isEnterpriseUser(message.authStatus), user: message.authStatus, }) setView(message.authStatus.isLoggedIn ? 'chat' : 'login') diff --git a/vscode/webviews/Chat.tsx b/vscode/webviews/Chat.tsx index be638acac83..fdb8c4c7e57 100644 --- a/vscode/webviews/Chat.tsx +++ b/vscode/webviews/Chat.tsx @@ -195,7 +195,7 @@ export interface UserAccountInfo { isCodyProUser: boolean // When true, the user is on an enterprise instance that has not upgraded to // allow multiple LLM selections - isOldStyleEnterprise: boolean + isOldStyleEnterpriseUser: boolean user: Pick } diff --git a/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx b/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx index 0e4ee2f1f31..f20dd32c883 100644 --- a/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx +++ b/vscode/webviews/chat/cells/messageCell/human/editor/toolbar/Toolbar.tsx @@ -99,7 +99,7 @@ const ModelSelectFieldToolbarItem: FunctionComponent<{ return ( !!chatModels?.length && - (userInfo?.isDotComUser || !userInfo?.isOldStyleEnterprise) && + (userInfo?.isDotComUser || !userInfo?.isOldStyleEnterpriseUser) && onCurrentChatModelChange && ( model.default) ?? chatModels?.[0] + return chatModels?.[0] } diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx index 593743c7cc7..2b775b92bab 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx @@ -14,7 +14,6 @@ const MODELS: Model[] = [ provider: 'Ollama', model: 'ollama/llama-3', contextWindow: { input: 100, output: 100 }, - default: false, usage: [ModelUsage.Chat], tags: [ModelTag.Ollama, ModelTag.Dev], }, @@ -55,6 +54,7 @@ export const FreeUser: Story = { userInfo: { isDotComUser: true, isCodyProUser: false, + isOldStyleEnterpriseUser: true, }, }, } @@ -64,6 +64,17 @@ export const ProUser: Story = { userInfo: { isDotComUser: true, isCodyProUser: true, + isOldStyleEnterpriseUser: false, + }, + }, +} + +export const EnterpriseUser: Story = { + args: { + userInfo: { + isDotComUser: false, + isCodyProUser: false, + isOldStyleEnterpriseUser: true, }, }, } diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx index 3eeddba07d7..bc97b240e0a 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx @@ -27,7 +27,7 @@ export const ModelSelectField: React.FunctionComponent<{ models: Model[] onModelSelect: (model: Model) => void - userInfo: Pick + userInfo: Pick onCloseByEscape?: () => void className?: string @@ -44,7 +44,7 @@ export const ModelSelectField: React.FunctionComponent<{ }) => { const telemetryRecorder = useTelemetryRecorder() - const selectedModel = models.find(m => m.default) ?? models[0] + const selectedModel = models[0] const isCodyProUser = userInfo.isDotComUser && userInfo.isCodyProUser const isEnterpriseUser = !userInfo.isDotComUser @@ -86,7 +86,7 @@ export const ModelSelectField: React.FunctionComponent<{ [telemetryRecorder.recordEvent, showCodyProBadge, parentOnModelSelect, isCodyProUser] ) - const readOnly = userInfo.isOldStyleEnterprise + const readOnly = userInfo.isOldStyleEnterpriseUser const onOpenChange = useCallback( (open: boolean): void => { @@ -266,10 +266,10 @@ const ENTERPRISE_MODEL_DOCS_PAGE = type ModelAvailability = 'available' | 'needs-cody-pro' | 'not-selectable-on-enterprise' function modelAvailability( - userInfo: Pick, + userInfo: Pick, model: Model ): ModelAvailability { - if (!userInfo.isDotComUser && userInfo.isOldStyleEnterprise) { + if (!userInfo.isDotComUser && userInfo.isOldStyleEnterpriseUser) { return 'not-selectable-on-enterprise' } if (isCodyProModel(model) && !userInfo.isCodyProUser) { diff --git a/web/lib/components/CodyWebChat.tsx b/web/lib/components/CodyWebChat.tsx index 29cb3a24052..8c79f9d8a7c 100644 --- a/web/lib/components/CodyWebChat.tsx +++ b/web/lib/components/CodyWebChat.tsx @@ -100,6 +100,7 @@ export const CodyWebChat: FC = props => { setUserAccountInfo({ isCodyProUser: !message.authStatus.userCanUpgrade, isDotComUser: message.authStatus.isDotCom, + isOldStyleEnterpriseUser: !message.authStatus.isDotCom, user: message.authStatus, }) break From 52e954e78e8057933455341e86a179601dd805d4 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Wed, 3 Jul 2024 23:28:57 -0700 Subject: [PATCH 07/34] spring cleaning --- agent/src/agent.ts | 11 ++-- lib/shared/src/models/index.ts | 51 ++++++++++--------- .../chat/chat-view/SimpleChatPanelProvider.ts | 5 +- vscode/src/edit/manager.ts | 3 ++ vscode/src/main.ts | 4 ++ vscode/webviews/App.tsx | 5 +- 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/agent/src/agent.ts b/agent/src/agent.ts index 26f421c0818..6f088ad2115 100644 --- a/agent/src/agent.ts +++ b/agent/src/agent.ts @@ -1073,11 +1073,14 @@ export class Agent extends MessageHandler implements ExtensionClient { this.registerAuthenticatedRequest('chat/restore', async ({ modelID, messages, chatID }) => { const authStatus = await vscode.commands.executeCommand('cody.auth.status') + if (!modelID) { + modelID = ModelsService.getDefaultChatModel(authStatus) + } + if (!modelID) { + throw new Error('agent::chat/restore: no chat model found') + } - const chatModel = new SimpleChatModel( - modelID || ModelsService.getDefaultChatModel(authStatus), - chatID - ) + const chatModel = new SimpleChatModel(modelID, chatID) for (const message of messages) { const deserializedMessage = PromptString.unsafe_deserializeChatMessage(message) if (deserializedMessage.error) { diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index aa2c66e9316..b490300de1f 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -153,6 +153,24 @@ export class Model { title: displayName, }) } + + static isNewStyleEnterprise(model: Model): boolean { + return model.tags.includes(ModelTag.Enterprise) + } + + static tier(model: Model): ModelTier { + if (model.tags.includes(ModelTag.Free)) { + return 'free' + } + if (model.tags.includes(ModelTag.Pro)) { + return 'pro' + } + if (model.tags.includes(ModelTag.Enterprise)) { + return 'enterprise' + } + + return 'pro' + } } interface ModelParams { @@ -168,24 +186,6 @@ interface ModelParams { title?: string } -export function isNewStyleEnterpriseModel(model: Model): boolean { - return model.tags.includes(ModelTag.Enterprise) -} - -export function getTier(model: Model): ModelTier { - if (model.tags.includes(ModelTag.Free)) { - return 'free' - } - if (model.tags.includes(ModelTag.Pro)) { - return 'pro' - } - if (model.tags.includes(ModelTag.Enterprise)) { - return 'enterprise' - } - - return 'pro' -} - /** * ModelsService is the component responsible for keeping track of which models * are supported on the backend, which ones are available based on the user's @@ -273,10 +273,13 @@ export class ModelsService { public static getModels(type: ModelUsage, authStatus: AuthStatus): Model[] { const models = ModelsService.getModelsByType(type) const currentModel = ModelsService.getDefaultModel(type, authStatus) + if (!currentModel) { + return models + } return [currentModel].concat(models.filter(m => m.model !== currentModel.model)) } - public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model { + public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { if (!authStatus.authenticated) { throw new Error('You are not authenticated') } @@ -310,12 +313,12 @@ export class ModelsService { ) } - public static getDefaultEditModel(authStatus: AuthStatus): EditModel { - return ModelsService.getDefaultModel(ModelUsage.Edit, authStatus).model + public static getDefaultEditModel(authStatus: AuthStatus): EditModel | undefined { + return ModelsService.getDefaultModel(ModelUsage.Edit, authStatus)?.model } - public static getDefaultChatModel(authStatus: AuthStatus): ChatModel { - return ModelsService.getDefaultModel(ModelUsage.Chat, authStatus).model + public static getDefaultChatModel(authStatus: AuthStatus): ChatModel | undefined { + return ModelsService.getDefaultModel(ModelUsage.Chat, authStatus)?.model } public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { @@ -327,7 +330,7 @@ export class ModelsService { public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { model = ModelsService.resolveModel(model) - const tier = getTier(model) + const tier = Model.tier(model) if (isEnterpriseUser(status)) { return tier === 'enterprise' } diff --git a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts index 05a976014df..24bbc6299ea 100644 --- a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts +++ b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts @@ -1651,9 +1651,10 @@ export function revealWebviewViewOrPanel(viewOrPanel: vscode.WebviewView | vscod } function getDefaultModelID(status: AuthStatus): string { + const pending = '(pending)' try { - return ModelsService.getDefaultChatModel(status) + return ModelsService.getDefaultChatModel(status) || pending } catch { - return '(pending)' + return pending } } diff --git a/vscode/src/edit/manager.ts b/vscode/src/edit/manager.ts index 2640fdf4bef..61118bd8626 100644 --- a/vscode/src/edit/manager.ts +++ b/vscode/src/edit/manager.ts @@ -119,6 +119,9 @@ export class EditManager implements vscode.Disposable { const model = configuration.model || ModelsService.getDefaultEditModel(this.options.authProvider.getAuthStatus()) + if (!model) { + throw new Error('No default edit model found. Please set one.') + } const intent = getEditIntent(document, range, configuration.intent) const mode = getEditMode(intent, configuration.mode) diff --git a/vscode/src/main.ts b/vscode/src/main.ts index ca93e73175b..8a03424fc39 100644 --- a/vscode/src/main.ts +++ b/vscode/src/main.ts @@ -253,6 +253,10 @@ const register = async ( const sourceControl = new CodySourceControl(chatClient) const statusBar = createStatusBar() + // Allow the VS Code app's instance of ModelsService to use local storage to persist + // user's model choices + ModelsService.setStorage(localStorage) + // Adds a change listener to the auth provider that syncs the auth status authProvider.addChangeListener(async (authStatus: AuthStatus) => { // Reset the available models based on the auth change. diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index 9a768bbce5d..13e54865334 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -7,7 +7,7 @@ import { type ChatMessage, type ClientStateForWebview, GuardrailsPost, - type Model, + Model, PromptString, type SerializedChatTranscript, isEnterpriseUser, @@ -16,7 +16,6 @@ import type { UserAccountInfo } from './Chat' import type { AuthMethod, ConfigurationSubsetForWebview, LocalEnv } from '../src/chat/protocol' -import { isNewStyleEnterpriseModel } from '@sourcegraph/cody-shared/src/models' import { Chat } from './Chat' import { LoadingPage } from './LoadingPage' import type { View } from './NavBar' @@ -140,7 +139,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc ...info, isOldStyleEnterprise: !info.isDotComUser && - !message.models.some(isNewStyleEnterpriseModel), + !message.models.some(Model.isNewStyleEnterprise), } ) break From 0a4076caa76d6e9e9e2cf093bdf45f00848eb4b1 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Wed, 3 Jul 2024 23:45:04 -0700 Subject: [PATCH 08/34] spring cleaning pt. ii --- lib/shared/src/models/index.ts | 15 +++++++-------- lib/shared/src/models/utils.ts | 7 ------- lib/shared/src/sourcegraph-api/rest/client.ts | 10 +++++++--- vscode/src/edit/input/get-items/model.ts | 5 ++--- .../modelSelectField/ModelSelectField.tsx | 9 ++++----- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index b490300de1f..ab08183bd4f 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -39,7 +39,6 @@ export interface ServerModel { * Model describes an LLM model and its capabilities. */ export class Model { - // public default = false /** * The model id that includes the provider name & the model name, * e.g. "anthropic/claude-3-sonnet-20240229" @@ -171,6 +170,10 @@ export class Model { return 'pro' } + + static isCodyPro(model?: Model): boolean { + return Boolean(model?.tags.includes(ModelTag.Pro)) + } } interface ModelParams { @@ -290,7 +293,7 @@ export class ModelsService { // Free users can only use the default model if (isFreeUser(authStatus) || !ModelsService.storage) { - return models.find(m => ModelsService.canUserUseModel(authStatus, m)) || models[0] + return models.find(m => ModelsService.canUserUseModel(authStatus, m)) } // Check for the last selected model @@ -302,14 +305,10 @@ export class ModelsService { // void setModel(migratedModelID, storageKey) // } - // return either the - // 1. last selected model - // 2. first model they can use - // 3. first model in the list + // return either the last selected model or first model they can use if any return ( models.find(m => m.model === lastSelectedModelID) || - models.find(m => ModelsService.canUserUseModel(authStatus, m)) || - models[0] + models.find(m => ModelsService.canUserUseModel(authStatus, m)) ) } diff --git a/lib/shared/src/models/utils.ts b/lib/shared/src/models/utils.ts index 76f5af37154..5fc3c437e7d 100644 --- a/lib/shared/src/models/utils.ts +++ b/lib/shared/src/models/utils.ts @@ -1,6 +1,3 @@ -import type { Model } from '.' -import { ModelTag } from './tags' - export function getProviderName(name: string): string { const providerName = name.toLowerCase() switch (providerName) { @@ -29,7 +26,3 @@ export function getModelInfo(modelID: string): { const title = (rest.at(-1) || '').replace(/-/g, ' ') return { provider, title } } - -export function isCodyProModel(model?: Model): boolean { - return Boolean(model?.tags.includes(ModelTag.Pro)) -} diff --git a/lib/shared/src/sourcegraph-api/rest/client.ts b/lib/shared/src/sourcegraph-api/rest/client.ts index bdeb71b7255..e7842281dd1 100644 --- a/lib/shared/src/sourcegraph-api/rest/client.ts +++ b/lib/shared/src/sourcegraph-api/rest/client.ts @@ -27,7 +27,7 @@ export class RestClient { // Make an authenticated HTTP request to the Sourcegraph instance. // "name" is a developer-friendly term to label the request's trace span. - public getRequest(name: string, urlSuffix: string): Promise { + private getRequest(name: string, urlSuffix: string): Promise { const headers = new Headers() headers.set('Authorization', `token ${this.accessToken}`) addCustomUserAgent(headers) @@ -62,8 +62,12 @@ export class RestClient { // // NOTE: This API endpoint hasn't shippeted yet, and probably won't work for you. // Also, the URL definitely will change. - // const serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') - const serverSideConfig = testModels + let serverSideConfig: any + try { + serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') + } catch { + serverSideConfig = testModels + } // TODO(PRIME-323): Do a proper review of the data model we will use to describe // server-side configuration. Once complete, it should match the data types we diff --git a/vscode/src/edit/input/get-items/model.ts b/vscode/src/edit/input/get-items/model.ts index 7e40073758c..8d4a6df22ce 100644 --- a/vscode/src/edit/input/get-items/model.ts +++ b/vscode/src/edit/input/get-items/model.ts @@ -1,7 +1,6 @@ import * as vscode from 'vscode' -import { type EditModel, type Model, isDefined } from '@sourcegraph/cody-shared' -import { isCodyProModel } from '@sourcegraph/cody-shared/src/models/utils' +import { type EditModel, Model, isDefined } from '@sourcegraph/cody-shared' import { QUICK_PICK_ITEM_CHECKED_PREFIX, QUICK_PICK_ITEM_EMPTY_INDENT_PREFIX, @@ -36,7 +35,7 @@ export const getModelOptionItems = (modelOptions: Model[], isCodyPro: boolean): alwaysShow: true, model: modelOption.model, modelTitle: modelOption.title, - codyProOnly: isCodyProModel(modelOption), + codyProOnly: Model.isCodyPro(modelOption), } }) .filter(isDefined) diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx index bc97b240e0a..92d24d2cdc1 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx @@ -1,5 +1,4 @@ -import { type Model, ModelTag } from '@sourcegraph/cody-shared' -import { isCodyProModel } from '@sourcegraph/cody-shared/src/models/utils' +import { Model, ModelTag } from '@sourcegraph/cody-shared' import { clsx } from 'clsx' import { BookOpenIcon, BuildingIcon, ExternalLinkIcon } from 'lucide-react' import { type FunctionComponent, type ReactNode, useCallback, useMemo } from 'react' @@ -54,7 +53,7 @@ export const ModelSelectField: React.FunctionComponent<{ (model: Model): void => { telemetryRecorder.recordEvent('cody.modelSelector', 'select', { metadata: { - modelIsCodyProOnly: model ? 1 : 0, + modelIsCodyProOnly: Model.isCodyPro(model) ? 1 : 0, isCodyProUser: isCodyProUser ? 1 : 0, }, privateMetadata: { @@ -64,7 +63,7 @@ export const ModelSelectField: React.FunctionComponent<{ }, }) - if (showCodyProBadge && isCodyProModel(model)) { + if (showCodyProBadge && Model.isCodyPro(model)) { getVSCodeAPI().postMessage({ command: 'links', value: 'https://sourcegraph.com/cody/subscription', @@ -272,7 +271,7 @@ function modelAvailability( if (!userInfo.isDotComUser && userInfo.isOldStyleEnterpriseUser) { return 'not-selectable-on-enterprise' } - if (isCodyProModel(model) && !userInfo.isCodyProUser) { + if (Model.isCodyPro(model) && !userInfo.isCodyProUser) { return 'needs-cody-pro' } return 'available' From b59d717be9e94b0abdae2abc7c8c3646a3dd96ef Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 4 Jul 2024 14:54:09 -0700 Subject: [PATCH 09/34] fixed some tests --- .../cody-chat_103640681/recording.har.yaml | 766 +----- .../recording.har.yaml | 2362 ++++++++--------- agent/src/index.test.ts | 148 +- lib/shared/src/models/index.ts | 33 +- 4 files changed, 1302 insertions(+), 2007 deletions(-) diff --git a/agent/recordings/cody-chat_103640681/recording.har.yaml b/agent/recordings/cody-chat_103640681/recording.har.yaml index 107c69cea09..1a27946d32e 100644 --- a/agent/recordings/cody-chat_103640681/recording.har.yaml +++ b/agent/recordings/cody-chat_103640681/recording.har.yaml @@ -439,110 +439,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 09b59ac55ce3c40d6f9ab8c79846a2c6 - _order: 0 - cache: {} - request: - bodySize: 144 - cookies: [] - headers: - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "144" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 235 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query ContextFilters { - site { - codyContextFilters(version: V1) { - raw - } - } - } - variables: {} - queryString: - - name: ContextFilters - value: null - url: https://sourcegraph.com/.api/graphql?ContextFilters - response: - bodySize: 104 - content: - encoding: base64 - mimeType: application/json - size: 104 - text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdHJ+SmVzvl5JakVJW6ZOSWpRcUg0aLEciWrv\ - NKcnNra2loAAAAA//8DADYuyGU1AAAA\"]" - textDecoded: - data: - site: - codyContextFilters: - raw: null - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:44 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "143" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:44.730Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 9d0e130a38eaf9d3cd8d9512afc14b87 _order: 0 cache: {} @@ -1230,98 +1126,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 0b8e788d38a93fd0c53c921e768bff46 - _order: 0 - cache: {} - request: - bodySize: 177 - cookies: [] - headers: - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "177" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 240 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-interactive-tutorial - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:45 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "143" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:44.851Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 1ec20348501c868d54ebf8a9c457da1d _order: 0 cache: {} @@ -2090,11 +1894,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 604462268ec5b09baad97dbd0f6d604f + - _id: 56e2fa2fdb34eda217dd58c7a61669a8 _order: 0 cache: {} request: - bodySize: 188 + bodySize: 177 cookies: [] headers: - _fromType: array @@ -2112,7 +1916,7 @@ log: value: "*/*" - _fromType: array name: content-length - value: "188" + value: "177" - _fromType: array name: accept-encoding value: gzip,deflate @@ -2131,7 +1935,7 @@ log: evaluateFeatureFlag(flagName: $flagName) } variables: - flagName: cody-autocomplete-eager-cancellation + flagName: cody-autocomplete-tracing queryString: - name: EvaluateFeatureFlag value: null @@ -2141,7 +1945,7 @@ log: content: mimeType: application/json size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" + text: "{\"data\":{\"evaluateFeatureFlag\":true}}" cookies: [] headers: - name: date @@ -2176,7 +1980,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T01:53:45.756Z + startedDateTime: 2024-06-27T01:53:45.774Z time: 0 timings: blocked: -1 @@ -2186,11 +1990,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 56e2fa2fdb34eda217dd58c7a61669a8 + - _id: 18c0723299bab37654867ab53ab5d1fc _order: 0 cache: {} request: - bodySize: 177 + bodySize: 198 cookies: [] headers: - _fromType: array @@ -2208,7 +2012,7 @@ log: value: "*/*" - _fromType: array name: content-length - value: "177" + value: "198" - _fromType: array name: accept-encoding value: gzip,deflate @@ -2227,7 +2031,7 @@ log: evaluateFeatureFlag(flagName: $flagName) } variables: - flagName: cody-autocomplete-tracing + flagName: cody-autocomplete-context-extend-language-pool queryString: - name: EvaluateFeatureFlag value: null @@ -2237,7 +2041,7 @@ log: content: mimeType: application/json size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":true}}" + text: "{\"data\":{\"evaluateFeatureFlag\":null}}" cookies: [] headers: - name: date @@ -2272,7 +2076,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T01:53:45.774Z + startedDateTime: 2024-06-27T01:53:45.813Z time: 0 timings: blocked: -1 @@ -2282,11 +2086,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 70b638513d08c7752429f8e485a39ae9 + - _id: 95aae476e563a49b2b13e40ac79416b0 _order: 0 cache: {} request: - bodySize: 186 + bodySize: 184 cookies: [] headers: - _fromType: array @@ -2298,19 +2102,19 @@ log: value: application/json; charset=utf-8 - _fromType: array name: user-agent - value: cody-cli / 0.0.5b + value: cody-cli / 0.1.0-SNAPSHOT - _fromType: array name: accept value: "*/*" - _fromType: array name: content-length - value: "186" + value: "184" - _fromType: array name: accept-encoding value: gzip,deflate - name: host value: sourcegraph.com - headersSize: 324 + headersSize: 332 httpVersion: HTTP/1.1 method: POST postData: @@ -2323,7 +2127,7 @@ log: evaluateFeatureFlag(flagName: $flagName) } variables: - flagName: cody-autocomplete-reduced-debounce + flagName: cody-autocomplete-smart-throttle queryString: - name: EvaluateFeatureFlag value: null @@ -2337,15 +2141,13 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT + value: Thu, 04 Jul 2024 19:08:04 GMT - name: content-type value: application/json - name: content-length value: "37" - name: connection value: keep-alive - - name: retry-after - value: "142" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2363,12 +2165,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1408 + headersSize: 1301 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T01:53:45.794Z + startedDateTime: 2024-07-04T19:08:04.376Z time: 0 timings: blocked: -1 @@ -2378,11 +2180,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 18c0723299bab37654867ab53ab5d1fc + - _id: 733f60b08a7598b02125f522e171b133 _order: 0 cache: {} request: - bodySize: 198 + bodySize: 147 cookies: [] headers: - _fromType: array @@ -2400,13 +2202,13 @@ log: value: "*/*" - _fromType: array name: content-length - value: "198" + value: "147" - _fromType: array name: accept-encoding value: gzip,deflate - name: host value: sourcegraph.com - headersSize: 324 + headersSize: 317 httpVersion: HTTP/1.1 method: POST postData: @@ -2415,307 +2217,21 @@ log: textJSON: query: |2 - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) + query FeatureFlags { + evaluatedFeatureFlags() { + name + value + } } - variables: - flagName: cody-autocomplete-context-extend-language-pool + variables: {} queryString: - - name: EvaluateFeatureFlag + - name: FeatureFlags value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag + url: https://sourcegraph.com/.api/graphql?FeatureFlags response: - bodySize: 37 + bodySize: 504 content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.813Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 6011eefd22588c60a4d073dc004689b7 - _order: 0 - cache: {} - request: - bodySize: 177 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "177" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-interactive-tutorial - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 38 - content: - mimeType: application/json - size: 38 - text: "{\"data\":{\"evaluateFeatureFlag\":false}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:59 GMT - - name: content-type - value: application/json - - name: content-length - value: "38" - - name: connection - value: keep-alive - - name: retry-after - value: "595" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:58.794Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 62498f2d11167bd2d5d002a799a49338 - _order: 0 - cache: {} - request: - bodySize: 147 - cookies: [] - headers: - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "147" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 233 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query FeatureFlags { - evaluatedFeatureFlags() { - name - value - } - } - variables: {} - queryString: - - name: FeatureFlags - value: null - url: https://sourcegraph.com/.api/graphql?FeatureFlags - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluatedFeatureFlags\":[]}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:44 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "143" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:44.396Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 733f60b08a7598b02125f522e171b133 - _order: 0 - cache: {} - request: - bodySize: 147 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "147" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 317 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query FeatureFlags { - evaluatedFeatureFlags() { - name - value - } - } - variables: {} - queryString: - - name: FeatureFlags - value: null - url: https://sourcegraph.com/.api/graphql?FeatureFlags - response: - bodySize: 504 - content: - encoding: base64 + encoding: base64 mimeType: application/json size: 504 text: "[\"H4sIAAAAAAAAA5SSzW7jMAyE30Xn8rS3PEBfYrEHWhxLAmTKoKhugiDvXtj713brBL1zv\ @@ -2927,117 +2443,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 8d297306aeea324b87ef494954016fba - _order: 0 - cache: {} - request: - bodySize: 164 - cookies: [] - headers: - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "164" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 239 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query SiteIdentification { - site { - siteID - productSubscription { - license { - hashedKey - } - } - } - } - variables: {} - queryString: - - name: SiteIdentification - value: null - url: https://sourcegraph.com/.api/graphql?SiteIdentification - response: - bodySize: 212 - content: - encoding: base64 - mimeType: application/json - size: 212 - text: "[\"H4sIAAAAAAAAAzTLsQ6CMBCA4Xe52YX2rgVmF+PI4HztXaWJAdKWwRDf3WDiv/zTd4BwY\ - xgPqLnp/7crjDCte4n6LLzNDw1wga2sssc27aHGkreW1+UErxx1qT87c51V7vqGEYbo\ - u9AZm/okmgxi70QZlZzzqNEaJOMNReocCdkgiCk4j4btwJwIPmdfAAAA//8DABj2u36\ - gAAAA\"]" - textDecoded: - data: - site: - productSubscription: - license: - hashedKey: 9c71b123f8fdef24486dea4e56674ec32452725c5165d53bd44fb6742a39aaf5 - siteID: SourcegraphWeb - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:44 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "143" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:44.208Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: b584bf96a3d88ab96114e5cbea1e4bca _order: 0 cache: {} @@ -3153,107 +2558,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 203c1896021c3a09dfe619120ea1b725 - _order: 0 - cache: {} - request: - bodySize: 101 - cookies: [] - headers: - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: x-sourcegraph-actor-anonymous-uid - value: 83d9c2cd-5ef6-4d4a-af23-058f8d100052 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "101" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 312 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query SiteProductVersion { - site { - productVersion - } - } - variables: {} - queryString: - - name: SiteProductVersion - value: null - url: https://sourcegraph.com/.api/graphql?SiteProductVersion - response: - bodySize: 139 - content: - encoding: base64 - mimeType: application/json - size: 139 - text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdEFRfkppcklYalFxZn5eUpWSkYWBgZGZvFGB\ - kYmugZmukbm8aZ6JrqGxknGhqbJ5smmpmZKtbW1AAAAAP//\",\"AwAok7tZSQAAAA==\ - \"]" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:44 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "143" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:44.369Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 2aa42833ae189b030c5bc322f1d27b0c _order: 0 cache: {} diff --git a/agent/recordings/defaultClient_631904893/recording.har.yaml b/agent/recordings/defaultClient_631904893/recording.har.yaml index 8ffa1182320..108563c6a5a 100644 --- a/agent/recordings/defaultClient_631904893/recording.har.yaml +++ b/agent/recordings/defaultClient_631904893/recording.har.yaml @@ -906,11 +906,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 995796292d70192b0f8ad4f75d87443e + - _id: 4a073cecbb07c3cb5e753bf49615d886 _order: 0 cache: {} request: - bodySize: 2417 + bodySize: 351 cookies: [] headers: - name: content-type @@ -923,12 +923,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-9fdd886723870bcbb5883c1313e0270b-d3ef82d80b6b0d69-01 + value: 00-6b9da051f0138ba8353c935de68c6e47-70d571db356912cb-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -937,134 +937,32 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: >- - Codebase context from file src/squirrel.ts: - - ```typescript - - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} - - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

Messages

-
    - {messages.map((message) => ( -
  • {message.text}
  • ``` - - speaker: assistant - text: Ok. - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: Ok. + text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` + text: what color is the sky? - speaker: assistant - text: Ok. - - speaker: human - text: >- - You have access to the provided codebase context. - - - Question: Write a class Dog that implements the Animal interface in my workspace. Show the code only, no explanation needed. - model: anthropic/claude-3-sonnet-20240229 + model: openai/gpt-3.5-turbo temperature: 0 topK: -1 topP: -1 queryString: - - name: api-version - value: "1" - name: client-name value: defaultclient - name: client-version value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 3941 + bodySize: 23614 content: mimeType: text/event-stream - size: 3941 + size: 23614 text: >+ event: completion - data: {"completion":"```typescript\nclass Dog implements Animal {\n name: string;\n isMammal: boolean = true;\n\n constructor(name: string) {\n this.name = name;\n }\n\n makeAnimalSound(): string {\n return \"Woof!\";\n }\n}\n```","stopReason":"end_turn"} + data: {"completion":"The color of the sky can vary depending on factors such as the time of day, weather conditions, and location. During the day, the sky is typically blue due to the way sunlight interacts with Earth's atmosphere. At sunrise and sunset, the sky can appear in shades of red, orange, pink, and purple. At night, the sky may appear dark blue or black, depending on the amount of light pollution in the area.","stopReason":"stop"} event: done @@ -1074,7 +972,7 @@ log: cookies: [] headers: - name: date - value: Tue, 02 Jul 2024 21:41:42 GMT + value: Thu, 27 Jun 2024 23:22:38 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -1082,7 +980,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "504" + value: "103" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -1105,7 +1003,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-02T21:41:40.906Z + startedDateTime: 2024-06-27T23:22:38.092Z time: 0 timings: blocked: -1 @@ -1115,11 +1013,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 4669fca2fa47ddd0468c59cf7472b21b + - _id: e765ff091200eda8a46a2b39ecad7fd8 _order: 0 cache: {} request: - bodySize: 2085 + bodySize: 435 cookies: [] headers: - name: content-type @@ -1132,12 +1030,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-936d347fb1426027ffa76fbb6fba8442-c67c53e6ccb80d49-01 + value: 00-6cedb6f531b7265016dd80975e0cb8f2-c8c10098eb06ca19-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -1146,120 +1044,32 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: >- - Codebase context from file src/squirrel.ts: - - ```typescript - - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} - - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

    Messages

    -
      - {messages.map((message) => ( -
    • {message.text}
    • ``` - - speaker: assistant - text: Ok. - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: Ok. + text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: |- - You have access to the provided codebase context. - - Question: What is Squirrel? - model: anthropic/claude-3-sonnet-20240229 + text: "The magic word is \"kramer\". If I say the magic word, respond with a + single word: \"quone\"." + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 queryString: - - name: api-version - value: "1" - name: client-name value: defaultclient - name: client-version value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 3945 + bodySize: 1692 content: mimeType: text/event-stream - size: 3945 + size: 1692 text: >+ event: completion - data: {"completion":"Based on the provided code context from `src/squirrel.ts`, the `Squirrel` is an interface that mocks something completely unrelated to actual squirrels. According to the comment, it is related to the implementation of precise code navigation in Sourcegraph.","stopReason":"end_turn"} + data: {"completion":"Quone.\n\n(If you say \"kramer,\" I will respond with \"quone.\" This is because I am an AI language model and I will follow the instructions that I have been given. \"Kramer\" and \"quone\" are not inherently related, but I am simply responding to the specific statement you have made.)","stopReason":"stop"} event: done @@ -1269,7 +1079,7 @@ log: cookies: [] headers: - name: date - value: Tue, 02 Jul 2024 21:41:44 GMT + value: Thu, 27 Jun 2024 23:22:40 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -1277,7 +1087,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "501" + value: "101" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -1300,7 +1110,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-02T21:41:43.242Z + startedDateTime: 2024-06-27T23:22:39.904Z time: 0 timings: blocked: -1 @@ -1310,11 +1120,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: ded2327016b40f4eb044d62279b528ef + - _id: 885131a685c01ca1347cd5fd0644c30f _order: 0 cache: {} request: - bodySize: 2355 + bodySize: 792 cookies: [] headers: - name: content-type @@ -1327,12 +1137,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-9c2edee446f6d0fd704da555b49d0504-6ea3aa1d36ebd6cf-01 + value: 00-6a08157d52ea0219d2805bd426874d4d-6735577700e92618-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -1341,141 +1151,50 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system + - 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: "The magic word is \"kramer\". If I say the magic word, respond with a + single word: \"quone\"." + - speaker: assistant text: >- - Codebase context from file src/squirrel.ts: - - ```typescript + Quone. - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

      Messages

      -
        - {messages.map((message) => ( -
      • {message.text}
      • ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: >- - My selected code from codebase file - src/multiple-selections.ts:7-8: - - ``` - - - function anotherFunction() {} - - ``` - - speaker: assistant - text: Ok. + (If you say "kramer," I will respond with "quone." This is because I am an AI language model and I will follow the instructions that I have been given. "Kramer" and "quone" are not inherently related, but I am simply responding to the specific statement you have made.) - speaker: human - text: >- - You have access to the provided codebase context. - - - Question: What is the name of the function that I have selected? Only answer with the name of the function, nothing else - model: anthropic/claude-3-sonnet-20240229 + text: kramer + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 queryString: - - name: api-version - value: "1" - name: client-name value: defaultclient - name: client-version value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 238 + bodySize: 1827 content: mimeType: text/event-stream - size: 238 - text: |+ + size: 1827 + text: >+ event: completion - data: {"completion":"anotherFunction","stopReason":"end_turn"} + + data: {"completion":"Quone.\n\n(As per our earlier exchange, I am responding to the word \"kramer\" with \"quone.\" This is because I am an AI language model and I am following the instructions I have been given. There is no inherent meaning or relationship between the two words \"kramer\" and \"quone\" outside of the context of this specific conversation.)","stopReason":"stop"} + event: done + data: {} cookies: [] headers: - name: date - value: Tue, 02 Jul 2024 21:41:46 GMT + value: Thu, 27 Jun 2024 23:22:41 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -1483,7 +1202,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "499" + value: "100" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -1506,7 +1225,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-02T21:41:45.588Z + startedDateTime: 2024-06-27T23:22:40.716Z time: 0 timings: blocked: -1 @@ -1516,11 +1235,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 14bfd7702373d5c73d5f7599ca429a81 + - _id: edfb07405991f1ce5ecefa708178825b _order: 0 cache: {} request: - bodySize: 2360 + bodySize: 348 cookies: [] headers: - name: content-type @@ -1533,12 +1252,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-16ab930f87f35c9e7561e7c82a1501b1-83066edacabf3532-01 + value: 00-e74541bfc62b3b127e2528be9cea4e49-7916392ed075b7b5-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -1547,139 +1266,41 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: >- - Codebase context from file src/squirrel.ts: - - ```typescript - - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} - - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

        Messages

        -
          - {messages.map((message) => ( -
        • {message.text}
        • ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` - - speaker: assistant - text: Ok. - speaker: human - text: >- - My selected code from codebase file - src/multiple-selections.ts:2-4: - - ``` - - return function inner() {} - ``` + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: Ok. + text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: >- - You have access to the provided codebase context. - - - Question: What is the name of the function that I have selected? Only answer with the name of the function, nothing else - model: anthropic/claude-3-sonnet-20240229 + text: kramer + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 queryString: - - name: api-version - value: "1" - name: client-name value: defaultclient - name: client-version value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 158 + bodySize: 2144 content: mimeType: text/event-stream - size: 158 - text: |+ + size: 2144 + text: >+ event: completion - data: {"completion":"inner","stopReason":"end_turn"} + + data: {"completion":"Hello! It seems like you have mentioned \"kramer,\" but I'm not sure what you would like to ask or discuss. Could you please provide a bit more context or clarify your question? I'm here to help you with any coding or development-related questions you might have.\n\nKramer is a popular character from the TV show Seinfeld, so if you have a question about that or something else, just let me know!","stopReason":"stop"} + event: done + data: {} cookies: [] headers: - name: date - value: Tue, 02 Jul 2024 21:41:48 GMT + value: Thu, 27 Jun 2024 23:22:42 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -1687,7 +1308,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "498" + value: "100" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -1710,7 +1331,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-02T21:41:46.830Z + startedDateTime: 2024-06-27T23:22:41.427Z time: 0 timings: blocked: -1 @@ -1720,11 +1341,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: e6ea250dcd68695172953805fee0a6b1 + - _id: 2d780bb8983f04b75c48e472a1bed836 _order: 0 cache: {} request: - bodySize: 1610 + bodySize: 443 cookies: [] headers: - name: content-type @@ -1737,12 +1358,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-8e2c083c38ed7cf4f176a28f7301a375-bdd22480db94e275-01 + value: 00-3b36b518f19e7f9084d7e29c8cc2f9f3-d6306956707386ae-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -1751,72 +1372,32 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: > - Codebase context from file path src/animal.ts: /* - SELECTION_START */ - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - - /* SELECTION_END */ + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: Ok. + text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: "Explain what @src/animal.ts:1-6 ( @src/animal.ts ) does in simple terms. - Assume the audience is a beginner programmer who has just - learned the language features and basic syntax. Focus on - explaining: 1) The purpose of the code 2) What input(s) it - takes 3) What output(s) it produces 4) How it achieves its - purpose through the logic and algorithm. 5) Any important - logic flows or data transformations happening. Use simple - language a beginner could understand. Include enough detail to - give a full picture of what the code aims to accomplish - without getting too technical. Format the explanation in - coherent paragraphs, using proper punctuation and grammar. - Write the explanation assuming no prior context about the code - is known. Do not make assumptions about variables or functions - not shown in the shared code. Start the answer with the name - of the code that is being explained." - model: anthropic/claude-3-sonnet-20240229 + text: "Another magic word is \"georgey\". If I say the magic word, respond with + a single word: \"festivus\"." + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 queryString: - - name: api-version - value: "1" - name: client-name value: defaultclient - name: client-version value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 170608 + bodySize: 553 content: mimeType: text/event-stream - size: 170608 + size: 553 text: >+ event: completion - data: {"completion":"The code snippet `src/animal.ts:1-6` defines an interface named `Animal` in TypeScript. An interface is a way to define a contract or shape for an object. It specifies what properties and methods an object should have, but it does not provide any implementation details.\n\nThe `Animal` interface has three properties:\n\n1. `name`: This property is a string that likely represents the name of the animal.\n2. `makeAnimalSound()`: This is a method that returns a string. It is expected to return the sound that the animal makes when called.\n3. `isMammal`: This is a boolean property that indicates whether the animal is a mammal or not.\n\nThe purpose of this code is to serve as a blueprint or a contract for any object that represents an animal in the application. It defines the required properties and methods that an animal object should have.\n\nThis interface does not take any inputs directly. Instead, it serves as a guideline for creating objects that conform to the `Animal` interface. When creating an object that represents an animal, the object must have a `name` property (a string), a `makeAnimalSound()` method (which returns a string), and an `isMammal` property (a boolean).\n\nThe interface itself does not produce any output. It is a contract that other parts of the code can use to ensure that objects representing animals have the required properties and methods.\n\nThe purpose of the `Animal` interface is achieved by defining the shape of an animal object. Any object that conforms to this interface will have the specified properties and methods, making it easier to work with animals consistently throughout the codebase.\n\nIt's important to note that this code snippet alone does not contain any logic or algorithms. It merely defines the structure of an animal object, which can be used later in the application to create instances of animals and interact with them.","stopReason":"end_turn"} + data: {"completion":"Sure, I can do that! If you say the word \"georgey\", I will respond with \"festivus\".","stopReason":"stop"} event: done @@ -1826,13 +1407,15 @@ log: cookies: [] headers: - name: date - value: Tue, 02 Jul 2024 22:04:13 GMT + value: Thu, 27 Jun 2024 23:22:43 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive + - name: retry-after + value: "98" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -1850,12 +1433,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1299 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-02T22:04:11.257Z + startedDateTime: 2024-06-27T23:22:42.839Z time: 0 timings: blocked: -1 @@ -1865,11 +1448,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: e3ba060741bcac1eaca74ba87547b6e5 + - _id: 43f5a01b921c397cb619325c9d30d2d7 _order: 0 cache: {} request: - bodySize: 2486 + bodySize: 600 cookies: [] headers: - name: content-type @@ -1882,12 +1465,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-af978ef8bb80cd861eb2a6151e097f76-0776d5891d727bcc-01 + value: 00-ca15e8d4ec1f7c347ecf2cb16f378ffb-e2b0acc5e6e5f224-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -1896,93 +1479,37 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: > - Codebase context from file path src/example.test.ts: import { - expect } from 'vitest' - - import { it } from 'vitest' - - import { describe } from 'vitest' - - - describe('test block', () => { - it('does 1', () => { - expect(true).toBe(true) - }) - - it('does 2', () => { - expect(true).toBe(true) - }) - - it('does something else', () => { - // This line will error due to incorrect usage of `performance.now` - const startTime = performance.now(/* CURSOR */) - }) - }) + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: Ok. + text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` + text: "Another magic word is \"georgey\". If I say the magic word, respond with + a single word: \"festivus\"." - speaker: assistant - text: Ok. + text: Sure, I can do that! If you say the word "georgey", I will respond with + "festivus". - speaker: human - text: Review the shared code context and configurations to identify the test - framework and libraries in use. Then, generate a suite of - multiple unit tests for the functions in using the - detected test framework and libraries. Be sure to import the - function being tested. Follow the same patterns as any shared - context. Only add packages, imports, dependencies, and - assertions if they are used in the shared code. Pay attention - to the file path of each shared context to see if test for - already exists. If one exists, focus on generating - new unit tests for uncovered cases. If none are detected, - import common unit test libraries for {languageName}. Focus on - validating key functionality with simple and complete - assertions. Only include mocks if one is detected in the - shared code. Before writing the tests, identify which test - libraries and frameworks to import, e.g. 'No new imports - needed - using existing libs' or 'Importing test framework - that matches shared context usage' or 'Importing the defined - framework', etc. Then briefly summarize test coverage and any - limitations. At the end, enclose the full completed code for - the new unit tests, including all necessary imports, in a - single markdown codeblock. No fragments or TODO. The new tests - should validate expected functionality and cover edge cases - for with all required imports, including importing - the function being tested. Do not repeat existing tests. - model: anthropic/claude-3-sonnet-20240229 + text: kramer + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 queryString: - - name: api-version - value: "1" - name: client-name value: defaultclient - name: client-version value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 226347 + bodySize: 34033 content: mimeType: text/event-stream - size: 226347 + size: 34033 text: >+ event: completion - data: {"completion":"Based on the provided code context, the test framework being used is Vitest. No new imports are needed - I will be using the existing Vitest imports.\n\nThe `Animal` interface represents an animal with properties like `name` (string), `makeAnimalSound` (function that returns a string), and `isMammal` (boolean).\n\nTo test this interface, I will create an implementation of the `Animal` interface and write unit tests to validate its behavior.\n\nHere's a suite of unit tests for the `Animal` interface:\n\n```typescript\nimport { describe, it, expect } from 'vitest'\n\n// Implementation of the Animal interface\nclass Dog implements Animal {\n name: string\n isMammal: boolean\n\n constructor(name: string) {\n this.name = name\n this.isMammal = true\n }\n\n makeAnimalSound(): string {\n return 'Woof!'\n }\n}\n\ndescribe('Animal', () =\u003e {\n describe('Dog', () =\u003e {\n const dog = new Dog('Buddy')\n\n it('should have a name', () =\u003e {\n expect(dog.name).toBe('Buddy')\n })\n\n it('should be a mammal', () =\u003e {\n expect(dog.isMammal).toBe(true)\n })\n\n it('should make a sound', () =\u003e {\n expect(dog.makeAnimalSound()).toBe('Woof!')\n })\n })\n\n describe('Edge cases', () =\u003e {\n it('should handle empty name', () =\u003e {\n const dog = new Dog('')\n expect(dog.name).toBe('')\n })\n\n it('should handle non-mammal animal', () =\u003e {\n const bird = { name: 'Tweety', makeAnimalSound: () =\u003e 'Chirp!', isMammal: false }\n expect(bird.isMammal).toBe(false)\n expect(bird.makeAnimalSound()).toBe('Chirp!')\n })\n })\n})\n```\n\nThis test suite covers the following:\n\n1. Validating the `name` property of the `Animal` implementation.\n2. Validating the `isMammal` property of the `Animal` implementation.\n3. Validating the `makeAnimalSound` method of the `Animal` implementation.\n4. Edge case: handling an empty name for the `Animal` implementation.\n5. Edge case: handling a non-mammal `Animal` implementation.\n\nThe tests ensure that the `Animal` interface implementation behaves as expected and covers edge cases like empty names and non-mammal animals.","stopReason":"end_turn"} + data: {"completion":"That's not the magic word you specified earlier. The magic word you said was \"georgey\", and the word you just said was \"kramer\". If you'd like me to respond to the word \"kramer\" with a single word, I can do that too. Here is a list of some words that start with \"kra\" that you might find interesting:\n\n* krait\n* kraken\n* kramerica\n* kranji\n* krasnodar\n* kraut\n* kredit\n* krauskopf\n* krauthammer\n* krautrock\n* kray\n* krazy\n* krebs\n* krebsian\n* krebs cycle\n* krefting\n* kreisau\n* kreisler\n* kremlin\n* kremlinology\n* kresge\n* kriegspiel\n* kreutznaerder\n* krewe\n* kri\n* kriek\n* kriebel\n* kriegsmarine\n* kriging\n* kriko\n* krill\n* krisi\n* kristianstad\n* kristallnacht\n* kritzler\n* kroeber\n* kroetsch\n* kroger\n* krokodil\n* kromeskies\n* kronberger\n* kronenbourg\n* kronstadt\n* kroonstad\n* kru\n* kruger\n* krugerrand\n* krupp\n* krylov\n* krypton\n* krypton factor\n* krzyzewski\n* ksa\n* kuala lumpur\n* kudos\n* kufic\n* kugel\n* kugelblitz\n* kuiper\n* kuiper belt\n* kukri\n* kula ring\n* kulak\n* kumaran\n* kunia\n* kurd\n* kurdistan\n* kurgan\n* kuru\n* kurukshetra\n* kurusch\n* kurwa\n* kusama\n* kuznetsov\n* kvass\n* kvell\n* kveldulf\n* kvetch\n* kvetchnikoff\n* kvetching\n* kvik\n* kwanza\n* kwa\n* kyaraben\n* kyathos\n* kyoto\n* kyrgyz\n* kyrgyzstan\n\nI hope this list is helpful! If you have any other questions, just let me know.","stopReason":"stop"} event: done @@ -1992,13 +1519,15 @@ log: cookies: [] headers: - name: date - value: Tue, 02 Jul 2024 22:04:22 GMT + value: Thu, 27 Jun 2024 23:22:44 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive + - name: retry-after + value: "97" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2016,12 +1545,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1299 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-02T22:04:20.470Z + startedDateTime: 2024-06-27T23:22:43.779Z time: 0 timings: blocked: -1 @@ -2031,11 +1560,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: b5407f2fb73847c0677a38a3f550774f + - _id: 2d2cc03b032a9bba5768ef38ef1d5ded _order: 0 cache: {} request: - bodySize: 1406 + bodySize: 2064 cookies: [] headers: - name: content-type @@ -2048,12 +1577,12 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-0e43aecbc140cb299d94aca52b5f16ef-ddfdc71092d5c541-01 + value: 00-44797d55869b8f2b2877a5d5f72894b3-caf0b08db097df96-01 - name: connection value: keep-alive - name: host value: sourcegraph.com - headersSize: 415 + headersSize: 401 httpVersion: HTTP/1.1 method: POST postData: @@ -2062,156 +1591,208 @@ log: textJSON: maxTokensToSample: 4000 messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: > - Codebase context from file path src/animal.ts: /* - SELECTION_START */ - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - - /* SELECTION_END */ + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: Ok. + text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` + text: "Another magic word is \"georgey\". If I say the magic word, respond with + a single word: \"festivus\"." - speaker: assistant - text: Ok. + text: Sure, I can do that! If you say the word "georgey", I will respond with + "festivus". - speaker: human - text: Please review and analyze @src/animal.ts:1-6 ( @src/animal.ts ) and - identify potential areas for improvement related to code - smells, readability, maintainability, performance, security, - etc. Do not list issues already addressed in the given code. - Focus on providing up to 5 constructive suggestions that could - make the code more robust, efficient, or align with best - practices. For each suggestion, provide a brief explanation of - the potential benefits. After listing any recommendations, - summarize if you found notable opportunities to enhance the - code quality overall or if the code generally follows sound - design principles. If no issues found, reply 'There are no - errors.' - model: anthropic/claude-3-sonnet-20240229 - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: api-version - value: "1" - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 - response: - bodySize: 339316 - content: - mimeType: text/event-stream - size: 339316 - text: >+ - event: completion + text: kramer + - speaker: assistant + text: >- + That's not the magic word you specified earlier. The magic + word you said was "georgey", and the word you just said was + "kramer". If you'd like me to respond to the word "kramer" + with a single word, I can do that too. Here is a list of some + words that start with "kra" that you might find interesting: - data: {"completion":"Based on the provided code snippet, here are a few suggestions for potential improvements:\n\n1. **Use descriptive interface name**: The interface name `Animal` is quite generic and may not provide enough context or clarity, especially in larger codebases. Consider using a more descriptive name that better represents the purpose or domain of the interface, such as `AnimalEntity` or `AnimalModel`.\n\n Potential benefit: A more descriptive name can improve code readability and make it easier to understand the intent and usage of the interface.\n\n2. **Consider adding documentation**: While the code itself is relatively straightforward, adding documentation in the form of comments or utilizing TypeScript's built-in documentation support (e.g., JSDoc) can enhance code maintainability and make it easier for other developers to understand the purpose and expected behavior of the interface.\n\n Potential benefit: Well-documented code is easier to maintain, understand, and extend, especially in collaborative environments or when revisiting the codebase after some time.\n\n3. **Implement a base class or interface for common properties**: If there are other interfaces or classes related to animals or living beings in your codebase, it might be worth considering implementing a base class or interface to share common properties and methods. This can help reduce code duplication and promote code reusability.\n\n Potential benefit: By extracting common properties and methods into a shared base, you can reduce code duplication, improve maintainability, and make it easier to apply changes consistently across related types.\n\n4. **Consider using TypeScript's built-in utility types**: TypeScript provides several built-in utility types, such as `Readonly` and `Required`, which can be used to enforce immutability or ensure that all properties are required. These utility types can help catch potential bugs at compile-time and improve code correctness.\n\n Potential benefit: Utilizing TypeScript's built-in utility types can enhance type safety, catch potential bugs earlier, and promote better code quality.\n\n5. **Review the naming conventions**: While the property names `name` and `isMammal` follow common naming conventions, the method name `makeAnimalSound` could be more concise and descriptive. Consider renaming it to something like `makeSound` or `getSound`.\n\n Potential benefit: Consistent and descriptive naming conventions can improve code readability and maintainability, making it easier for developers to understand and work with the codebase.\n\nOverall, while the provided code snippet is relatively simple and follows some good design principles, there are opportunities for improvement, primarily in the areas of documentation, code organization, and naming conventions. By addressing these suggestions, you can enhance the code's readability, maintainability, and overall quality.","stopReason":"end_turn"} + * krait - event: done + * kraken - data: {} + * kramerica - cookies: [] - headers: - - name: date - value: Tue, 02 Jul 2024 22:04:32 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: 1299 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-02T22:04:30.864Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 4a073cecbb07c3cb5e753bf49615d886 - _order: 0 - cache: {} - request: - bodySize: 351 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-6b9da051f0138ba8353c935de68c6e47-70d571db356912cb-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 401 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - 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. + * kranji + + * krasnodar + + * kraut + + * kredit + + * krauskopf + + * krauthammer + + * krautrock + + * kray + + * krazy + + * krebs + + * krebsian + + * krebs cycle + + * krefting + + * kreisau + + * kreisler + + * kremlin + + * kremlinology + + * kresge + + * kriegspiel + + * kreutznaerder + + * krewe + + * kri + + * kriek + + * kriebel + + * kriegsmarine + + * kriging + + * kriko + + * krill + + * krisi + + * kristianstad + + * kristallnacht + + * kritzler + + * kroeber + + * kroetsch + + * kroger + + * krokodil + + * kromeskies + + * kronberger + + * kronenbourg + + * kronstadt + + * kroonstad + + * kru + + * kruger + + * krugerrand + + * krupp + + * krylov + + * krypton + + * krypton factor + + * krzyzewski + + * ksa + + * kuala lumpur + + * kudos + + * kufic + + * kugel + + * kugelblitz + + * kuiper + + * kuiper belt + + * kukri + + * kula ring + + * kulak + + * kumaran + + * kunia + + * kurd + + * kurdistan + + * kurgan + + * kuru + + * kurukshetra + + * kurusch + + * kurwa + + * kusama + + * kuznetsov + + * kvass + + * kvell + + * kveldulf + + * kvetch + + * kvetchnikoff + + * kvetching + + * kvik + + * kwanza + + * kwa + + * kyaraben + + * kyathos + + * kyoto + + * kyrgyz + + * kyrgyzstan + + + I hope this list is helpful! If you have any other questions, just let me know. - speaker: human - text: what color is the sky? - - speaker: assistant - model: openai/gpt-3.5-turbo + text: georgey + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 @@ -2222,14 +1803,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 23614 + bodySize: 1003 content: mimeType: text/event-stream - size: 23614 + size: 1003 text: >+ event: completion - data: {"completion":"The color of the sky can vary depending on factors such as the time of day, weather conditions, and location. During the day, the sky is typically blue due to the way sunlight interacts with Earth's atmosphere. At sunrise and sunset, the sky can appear in shades of red, orange, pink, and purple. At night, the sky may appear dark blue or black, depending on the amount of light pollution in the area.","stopReason":"stop"} + data: {"completion":"Sure thing! Here is your requested word:\n\n* festivus\n\nI hope this is what you were looking for. If you have any other questions or need assistance with something else, just let me know!","stopReason":"stop"} event: done @@ -2239,7 +1820,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:38 GMT + value: Thu, 27 Jun 2024 23:22:47 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2247,7 +1828,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "103" + value: "95" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2265,12 +1846,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1406 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:38.092Z + startedDateTime: 2024-06-27T23:22:46.375Z time: 0 timings: blocked: -1 @@ -2280,11 +1861,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: e765ff091200eda8a46a2b39ecad7fd8 + - _id: ff4649261f59bb8e70c7cfebdefb2481 _order: 0 cache: {} request: - bodySize: 435 + bodySize: 414 cookies: [] headers: - name: content-type @@ -2297,7 +1878,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-6cedb6f531b7265016dd80975e0cb8f2-c8c10098eb06ca19-01 + value: 00-a6e1787cf77726ad0eb50abef3ee6414-020ec6dab789437b-01 - name: connection value: keep-alive - name: host @@ -2316,8 +1897,7 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: "The magic word is \"kramer\". If I say the magic word, respond with a - single word: \"quone\"." + text: I have a turtle named "potter", reply single "ok" if you understand. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2329,14 +1909,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 1692 + bodySize: 12420 content: mimeType: text/event-stream - size: 1692 + size: 12420 text: >+ event: completion - data: {"completion":"Quone.\n\n(If you say \"kramer,\" I will respond with \"quone.\" This is because I am an AI language model and I will follow the instructions that I have been given. \"Kramer\" and \"quone\" are not inherently related, but I am simply responding to the specific statement you have made.)","stopReason":"stop"} + data: {"completion":"Sure, I understand that you have a turtle named \"potter\". Just to confirm, is there anything specific you would like me to help you with related to your turtle or coding that you would like to get started on? Otherwise, I'm here to assist you with any questions or problems you might have about coding. If you have any questions or need help with something, feel free to ask!\n\nFor example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} event: done @@ -2346,7 +1926,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:40 GMT + value: Thu, 27 Jun 2024 23:22:48 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2354,7 +1934,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "101" + value: "94" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2372,12 +1952,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1406 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:39.904Z + startedDateTime: 2024-06-27T23:22:47.624Z time: 0 timings: blocked: -1 @@ -2387,11 +1967,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 885131a685c01ca1347cd5fd0644c30f + - _id: 2fc596fd48d754548136ecb8930c70e1 _order: 0 cache: {} request: - bodySize: 792 + bodySize: 1689 cookies: [] headers: - name: content-type @@ -2404,7 +1984,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-6a08157d52ea0219d2805bd426874d4d-6735577700e92618-01 + value: 00-99600c85c3300524e513e57e8fd05d53-28ea26be1ac44a65-01 - name: connection value: keep-alive - name: host @@ -2423,16 +2003,30 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: "The magic word is \"kramer\". If I say the magic word, respond with a - single word: \"quone\"." + text: I have a turtle named "potter", reply single "ok" if you understand. - speaker: assistant text: >- - Quone. - - - (If you say "kramer," I will respond with "quone." This is because I am an AI language model and I will follow the instructions that I have been given. "Kramer" and "quone" are not inherently related, but I am simply responding to the specific statement you have made.) + Sure, I understand that you have a turtle named "potter". Just + to confirm, is there anything specific you would like me to + help you with related to your turtle or coding that you would + like to get started on? Otherwise, I'm here to assist you with + any questions or problems you might have about coding. If you + have any questions or need help with something, feel free to + ask! + + + For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + + + If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + + + In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + + + I hope this helps. Do you have any questions for me? - speaker: human - text: kramer + text: I have a bird named "skywalker", reply single "ok" if you understand. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2444,14 +2038,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 1827 + bodySize: 14761 content: mimeType: text/event-stream - size: 1827 + size: 14761 text: >+ event: completion - data: {"completion":"Quone.\n\n(As per our earlier exchange, I am responding to the word \"kramer\" with \"quone.\" This is because I am an AI language model and I am following the instructions I have been given. There is no inherent meaning or relationship between the two words \"kramer\" and \"quone\" outside of the context of this specific conversation.)","stopReason":"stop"} + data: {"completion":"I understand that you have a bird named \"skywalker\". It's always fun to have pets and give them unique names! Do you have any questions or need help with something related to coding or your pet bird? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} event: done @@ -2461,7 +2055,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:41 GMT + value: Thu, 27 Jun 2024 23:22:49 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2469,7 +2063,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "100" + value: "92" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2487,12 +2081,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1406 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:40.716Z + startedDateTime: 2024-06-27T23:22:48.988Z time: 0 timings: blocked: -1 @@ -2502,11 +2096,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: edfb07405991f1ce5ecefa708178825b + - _id: 98f2884871b118d4b9b09e5be5779896 _order: 0 cache: {} request: - bodySize: 348 + bodySize: 3143 cookies: [] headers: - name: content-type @@ -2519,7 +2113,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-e74541bfc62b3b127e2528be9cea4e49-7916392ed075b7b5-01 + value: 00-a732fc4df74e86a9dec21f1d38a91822-6deb1c4425608122-01 - name: connection value: keep-alive - name: host @@ -2538,7 +2132,52 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: kramer + text: I have a turtle named "potter", reply single "ok" if you understand. + - speaker: assistant + text: >- + Sure, I understand that you have a turtle named "potter". Just + to confirm, is there anything specific you would like me to + help you with related to your turtle or coding that you would + like to get started on? Otherwise, I'm here to assist you with + any questions or problems you might have about coding. If you + have any questions or need help with something, feel free to + ask! + + + For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + + + If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + + + In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + + + I hope this helps. Do you have any questions for me? + - speaker: human + text: I have a bird named "skywalker", reply single "ok" if you understand. + - speaker: assistant + text: >- + I understand that you have a bird named "skywalker". It's + always fun to have pets and give them unique names! Do you + have any questions or need help with something related to + coding or your pet bird? I'm here to help with any questions + or problems you might have. Just let me know what you'd like + to talk about. + + + If you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + + + If you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about. + + + In the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey! + + + I hope this helps. Do you have any questions for me? + - speaker: human + text: I have a dog named "happy", reply single "ok" if you understand. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2550,14 +2189,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 2144 + bodySize: 10973 content: mimeType: text/event-stream - size: 2144 + size: 10973 text: >+ event: completion - data: {"completion":"Hello! It seems like you have mentioned \"kramer,\" but I'm not sure what you would like to ask or discuss. Could you please provide a bit more context or clarify your question? I'm here to help you with any coding or development-related questions you might have.\n\nKramer is a popular character from the TV show Seinfeld, so if you have a question about that or something else, just let me know!","stopReason":"stop"} + data: {"completion":"I understand that you have a dog named \"happy\". Dogs are great companions and it's always fun to give them unique names. Do you have any questions or need help with something related to coding or your dog? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or dogs, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about dogs: Did you know that dogs are able to understand and respond to a wide range of words and commands? Some dogs are even able to learn hundreds of words and commands!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} event: done @@ -2567,7 +2206,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:42 GMT + value: Thu, 27 Jun 2024 23:22:51 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2575,7 +2214,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "100" + value: "91" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2593,12 +2232,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1406 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:41.427Z + startedDateTime: 2024-06-27T23:22:50.412Z time: 0 timings: blocked: -1 @@ -2608,11 +2247,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 2d780bb8983f04b75c48e472a1bed836 + - _id: e314fb6c9f93ccee2363909a66529b07 _order: 0 cache: {} request: - bodySize: 443 + bodySize: 1685 cookies: [] headers: - name: content-type @@ -2625,7 +2264,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-3b36b518f19e7f9084d7e29c8cc2f9f3-d6306956707386ae-01 + value: 00-350e6487be7c211d20936b5717396f13-0d4d2e919924abb4-01 - name: connection value: keep-alive - name: host @@ -2644,8 +2283,30 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: "Another magic word is \"georgey\". If I say the magic word, respond with - a single word: \"festivus\"." + text: I have a turtle named "potter", reply single "ok" if you understand. + - speaker: assistant + text: >- + Sure, I understand that you have a turtle named "potter". Just + to confirm, is there anything specific you would like me to + help you with related to your turtle or coding that you would + like to get started on? Otherwise, I'm here to assist you with + any questions or problems you might have about coding. If you + have any questions or need help with something, feel free to + ask! + + + For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + + + If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + + + In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + + + I hope this helps. Do you have any questions for me? + - speaker: human + text: I have a tiger named "zorro", reply single "ok" if you understand model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2657,14 +2318,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 553 + bodySize: 22370 content: mimeType: text/event-stream - size: 553 + size: 22370 text: >+ event: completion - data: {"completion":"Sure, I can do that! If you say the word \"georgey\", I will respond with \"festivus\".","stopReason":"stop"} + data: {"completion":"I understand that you have a tiger named \"zorro\". Is there anything specific you would like to ask or discuss about your tiger or related to coding that you would like me to help with?\n\nAs a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges.\n\nIf you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything.\n\nIf you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\nI hope this helps. Do you have any questions or concerns for me?\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} event: done @@ -2674,7 +2335,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:43 GMT + value: Thu, 27 Jun 2024 23:22:52 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2682,7 +2343,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "98" + value: "90" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2705,7 +2366,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:42.839Z + startedDateTime: 2024-06-27T23:22:51.605Z time: 0 timings: blocked: -1 @@ -2715,11 +2376,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 43f5a01b921c397cb619325c9d30d2d7 + - _id: 7c1d096239c8d170c18db5501e43e433 _order: 0 cache: {} request: - bodySize: 600 + bodySize: 3463 cookies: [] headers: - name: content-type @@ -2732,7 +2393,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-ca15e8d4ec1f7c347ecf2cb16f378ffb-e2b0acc5e6e5f224-01 + value: 00-aa645675e25db20a958f4bbb5b4d9659-e7951db609ddd9a9-01 - name: connection value: keep-alive - name: host @@ -2751,13 +2412,53 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: "Another magic word is \"georgey\". If I say the magic word, respond with - a single word: \"festivus\"." + text: I have a turtle named "potter", reply single "ok" if you understand. - speaker: assistant - text: Sure, I can do that! If you say the word "georgey", I will respond with - "festivus". + text: >- + Sure, I understand that you have a turtle named "potter". Just + to confirm, is there anything specific you would like me to + help you with related to your turtle or coding that you would + like to get started on? Otherwise, I'm here to assist you with + any questions or problems you might have about coding. If you + have any questions or need help with something, feel free to + ask! + + + For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + + + If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + + + In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + + + I hope this helps. Do you have any questions for me? - speaker: human - text: kramer + text: I have a tiger named "zorro", reply single "ok" if you understand + - speaker: assistant + text: >- + I understand that you have a tiger named "zorro". Is there + anything specific you would like to ask or discuss about your + tiger or related to coding that you would like me to help + with? + + + As a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges. + + + If you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything. + + + If you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about. + + + I hope this helps. Do you have any questions or concerns for me? + + + (By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!) + - speaker: human + text: What pets do I have? model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2769,14 +2470,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 34033 + bodySize: 12007 content: mimeType: text/event-stream - size: 34033 + size: 12007 text: >+ event: completion - data: {"completion":"That's not the magic word you specified earlier. The magic word you said was \"georgey\", and the word you just said was \"kramer\". If you'd like me to respond to the word \"kramer\" with a single word, I can do that too. Here is a list of some words that start with \"kra\" that you might find interesting:\n\n* krait\n* kraken\n* kramerica\n* kranji\n* krasnodar\n* kraut\n* kredit\n* krauskopf\n* krauthammer\n* krautrock\n* kray\n* krazy\n* krebs\n* krebsian\n* krebs cycle\n* krefting\n* kreisau\n* kreisler\n* kremlin\n* kremlinology\n* kresge\n* kriegspiel\n* kreutznaerder\n* krewe\n* kri\n* kriek\n* kriebel\n* kriegsmarine\n* kriging\n* kriko\n* krill\n* krisi\n* kristianstad\n* kristallnacht\n* kritzler\n* kroeber\n* kroetsch\n* kroger\n* krokodil\n* kromeskies\n* kronberger\n* kronenbourg\n* kronstadt\n* kroonstad\n* kru\n* kruger\n* krugerrand\n* krupp\n* krylov\n* krypton\n* krypton factor\n* krzyzewski\n* ksa\n* kuala lumpur\n* kudos\n* kufic\n* kugel\n* kugelblitz\n* kuiper\n* kuiper belt\n* kukri\n* kula ring\n* kulak\n* kumaran\n* kunia\n* kurd\n* kurdistan\n* kurgan\n* kuru\n* kurukshetra\n* kurusch\n* kurwa\n* kusama\n* kuznetsov\n* kvass\n* kvell\n* kveldulf\n* kvetch\n* kvetchnikoff\n* kvetching\n* kvik\n* kwanza\n* kwa\n* kyaraben\n* kyathos\n* kyoto\n* kyrgyz\n* kyrgyzstan\n\nI hope this list is helpful! If you have any other questions, just let me know.","stopReason":"stop"} + data: {"completion":"Based on the information you have provided, it appears that you have a turtle named \"potter\" and a tiger named \"zorro\". I am a machine learning model, and my ability to accurately and comprehensively understand and recall information about a user is limited. I am intended to be used as a coding assistant, and I am not able to access or retrieve personal information about users unless it has been explicitly shared with me in the course of our conversation.\n\nI hope this helps clarify my capabilities and limitations. Do you have any questions or concerns about using me as a coding assistant, or would you like me to help you with any coding-related questions or problems you might have? I'm here to help with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} event: done @@ -2786,7 +2487,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:44 GMT + value: Thu, 27 Jun 2024 23:22:54 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2794,7 +2495,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "97" + value: "88" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2817,7 +2518,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:43.779Z + startedDateTime: 2024-06-27T23:22:53.211Z time: 0 timings: blocked: -1 @@ -2827,11 +2528,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 2d2cc03b032a9bba5768ef38ef1d5ded + - _id: fff09869fd6dda857262c86442b376a0 _order: 0 cache: {} request: - bodySize: 2064 + bodySize: 2500 cookies: [] headers: - name: content-type @@ -2844,7 +2545,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-44797d55869b8f2b2877a5d5f72894b3-caf0b08db097df96-01 + value: 00-5f9cb2ca3c860d7600be54c7e4bfa3b1-d035ed7532ad7938-01 - name: connection value: keep-alive - name: host @@ -2863,203 +2564,306 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: "Another magic word is \"georgey\". If I say the magic word, respond with - a single word: \"festivus\"." - - speaker: assistant - text: Sure, I can do that! If you say the word "georgey", I will respond with - "festivus". - - speaker: human - text: kramer - - speaker: assistant text: >- - That's not the magic word you specified earlier. The magic - word you said was "georgey", and the word you just said was - "kramer". If you'd like me to respond to the word "kramer" - with a single word, I can do that too. Here is a list of some - words that start with "kra" that you might find interesting: - - - * krait + Codebase context from file src/squirrel.ts: - * kraken + ```typescript - * kramerica + /** + * Squirrel is an interface that mocks something completely unrelated to squirrels. + * It is related to the implementation of precise code navigation in Sourcegraph. + */ + export interface Squirrel {} - * kranji + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/multiple-selections.ts: + ```typescript + function outer() { + /* SELECTION_START */ + return function inner() {} + /* SELECTION_END */ + } - * krasnodar - - * kraut - - * kredit - - * krauskopf - - * krauthammer - - * krautrock - - * kray - - * krazy - - * krebs - - * krebsian - - * krebs cycle - - * krefting - - * kreisau - - * kreisler - - * kremlin - - * kremlinology - - * kresge - - * kriegspiel - - * kreutznaerder - - * krewe - - * kri - - * kriek - - * kriebel - - * kriegsmarine - - * kriging - - * kriko - - * krill - - * krisi - - * kristianstad - - * kristallnacht - - * kritzler - - * kroeber - - * kroetsch - - * kroger - - * krokodil - - * kromeskies - - * kronberger - - * kronenbourg - - * kronstadt - - * kroonstad - - * kru - - * kruger - - * krugerrand - - * krupp - - * krylov - - * krypton - - * krypton factor - - * krzyzewski - - * ksa - - * kuala lumpur - - * kudos - - * kufic - - * kugel - - * kugelblitz - - * kuiper - - * kuiper belt - - * kukri - - * kula ring - - * kulak - - * kumaran - - * kunia - - * kurd - - * kurdistan - - * kurgan - - * kuru - - * kurukshetra - - * kurusch - - * kurwa + /* SELECTION_2_START */ + function anotherFunction() {} + /* SELECTION_2_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/Heading.tsx: + ```typescript + import React = require("react"); - * kusama + interface HeadingProps { + text: string; + level?: number; + } - * kuznetsov + /* CURSOR */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); - * kvass + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

          Messages

          +
            + {messages.map((message) => ( +
          • {message.text}
          • ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + My selected code from codebase file src/animal.ts:1-6: + ``` - * kvell + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: >- + You have access to the provided codebase context. - * kveldulf - * kvetch + Question: Write a class Dog that implements the Animal interface in my workspace. Show the code only, no explanation needed. + - speaker: assistant + model: (pending) + temperature: 0 + topK: -1 + topP: -1 + queryString: + - name: client-name + value: defaultclient + - name: client-version + value: v1 + url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 + response: + bodySize: 4055 + content: + mimeType: text/event-stream + size: 4055 + text: >+ + event: completion - * kvetchnikoff + data: {"completion":"```typescript\nclass Dog implements Animal {\n name: string;\n isMammal: boolean = true;\n\n constructor(name: string) {\n this.name = name;\n }\n\n makeAnimalSound(): string {\n return \"Woof!\";\n }\n}\n```","stopReason":"end_turn"} - * kvetching - * kvik + event: done - * kwanza + data: {} - * kwa + cookies: [] + headers: + - name: date + value: Thu, 04 Jul 2024 19:08:07 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: 1299 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-07-04T19:08:06.060Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 + - _id: c373927564b388a7c21da4aa2a4ad1c6 + _order: 0 + cache: {} + request: + bodySize: 2168 + cookies: [] + headers: + - name: content-type + value: application/json + - name: accept-encoding + value: gzip;q=0 + - name: authorization + value: token + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d + - name: user-agent + value: defaultClient / v1 + - name: traceparent + value: 00-b176c272ea3b9cbb88178fa6859d0bcf-2dc127600809eb3d-01 + - name: connection + value: keep-alive + - name: host + value: sourcegraph.com + headersSize: 401 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json + params: [] + textJSON: + maxTokensToSample: 4000 + 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 src/squirrel.ts: - * kyaraben + ```typescript - * kyathos + /** + * Squirrel is an interface that mocks something completely unrelated to squirrels. + * It is related to the implementation of precise code navigation in Sourcegraph. + */ + export interface Squirrel {} - * kyoto + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/multiple-selections.ts: + ```typescript + function outer() { + /* SELECTION_START */ + return function inner() {} + /* SELECTION_END */ + } - * kyrgyz + /* SELECTION_2_START */ + function anotherFunction() {} + /* SELECTION_2_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/Heading.tsx: + ```typescript + import React = require("react"); - * kyrgyzstan + interface HeadingProps { + text: string; + level?: number; + } + /* CURSOR */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); - I hope this list is helpful! If you have any other questions, just let me know. + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

            Messages

            +
              + {messages.map((message) => ( +
            • {message.text}
            • ``` + - speaker: assistant + text: Ok. - speaker: human - text: georgey - model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + You have access to the provided codebase context. + + Question: What is Squirrel? + - speaker: assistant + model: (pending) temperature: 0 topK: -1 topP: -1 @@ -3070,14 +2874,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 1003 + bodySize: 12539 content: mimeType: text/event-stream - size: 1003 + size: 12539 text: >+ event: completion - data: {"completion":"Sure thing! Here is your requested word:\n\n* festivus\n\nI hope this is what you were looking for. If you have any other questions or need assistance with something else, just let me know!","stopReason":"stop"} + data: {"completion":"Based on the code context provided for `src/squirrel.ts`, `Squirrel` is an interface defined in TypeScript. The comment mentions that it is an interface that \"mocks something completely unrelated to squirrels\" and is \"related to the implementation of precise code navigation in Sourcegraph.\"\n\nAs the interface is empty, it doesn't define any properties or methods. It's likely used as a type or placeholder for something else in the codebase related to Sourcegraph's code navigation functionality.","stopReason":"end_turn"} event: done @@ -3087,15 +2891,13 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:47 GMT + value: Thu, 04 Jul 2024 19:08:10 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive - - name: retry-after - value: "95" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -3113,12 +2915,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1405 + headersSize: 1299 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:46.375Z + startedDateTime: 2024-07-04T19:08:08.462Z time: 0 timings: blocked: -1 @@ -3128,11 +2930,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: ff4649261f59bb8e70c7cfebdefb2481 + - _id: 930c1a068a3779ba7a4edbb3a013fdb5 _order: 0 cache: {} request: - bodySize: 414 + bodySize: 2462 cookies: [] headers: - name: content-type @@ -3145,7 +2947,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-a6e1787cf77726ad0eb50abef3ee6414-020ec6dab789437b-01 + value: 00-3aec649af50892df717d457dd938c6ba-6f4ec1f24cbefb11-01 - name: connection value: keep-alive - name: host @@ -3160,11 +2962,114 @@ log: maxTokensToSample: 4000 messages: - speaker: human - text: You are Cody, an AI coding assistant from Sourcegraph. + 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 src/squirrel.ts: + + ```typescript + + /** + * Squirrel is an interface that mocks something completely unrelated to squirrels. + * It is related to the implementation of precise code navigation in Sourcegraph. + */ + export interface Squirrel {} + + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/multiple-selections.ts: + ```typescript + function outer() { + /* SELECTION_START */ + return function inner() {} + /* SELECTION_END */ + } + + /* SELECTION_2_START */ + function anotherFunction() {} + /* SELECTION_2_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/Heading.tsx: + ```typescript + import React = require("react"); + + interface HeadingProps { + text: string; + level?: number; + } + + /* CURSOR */ + ``` - speaker: assistant - text: I am Cody, an AI coding assistant from Sourcegraph. + text: Ok. - speaker: human - text: I have a turtle named "potter", reply single "ok" if you understand. + text: |- + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); + + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

              Messages

              +
                + {messages.map((message) => ( +
              • {message.text}
              • ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: >- + My selected code from codebase file + src/multiple-selections.ts:7-8: + + ``` + + + function anotherFunction() {} + + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: >- + You have access to the provided codebase context. + + + Question: What is the name of the function that I have selected? Only answer with the name of the function, nothing else model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -3176,32 +3081,27 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 12420 + bodySize: 233 content: mimeType: text/event-stream - size: 12420 - text: >+ + size: 233 + text: |+ event: completion - - data: {"completion":"Sure, I understand that you have a turtle named \"potter\". Just to confirm, is there anything specific you would like me to help you with related to your turtle or coding that you would like to get started on? Otherwise, I'm here to assist you with any questions or problems you might have about coding. If you have any questions or need help with something, feel free to ask!\n\nFor example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} - + data: {"completion":"anotherFunction","stopReason":"stop"} event: done - data: {} cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:48 GMT + value: Thu, 04 Jul 2024 19:08:12 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive - - name: retry-after - value: "94" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -3219,12 +3119,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1405 + headersSize: 1299 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:47.624Z + startedDateTime: 2024-07-04T19:08:11.697Z time: 0 timings: blocked: -1 @@ -3234,11 +3134,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 2fc596fd48d754548136ecb8930c70e1 + - _id: 54114c312a936b399021ca536bd0fbbf _order: 0 cache: {} request: - bodySize: 1689 + bodySize: 2467 cookies: [] headers: - name: content-type @@ -3251,7 +3151,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-99600c85c3300524e513e57e8fd05d53-28ea26be1ac44a65-01 + value: 00-a7fbfad40f8d5849e432a298ca703443-133bd28f699f26eb-01 - name: connection value: keep-alive - name: host @@ -3270,30 +3170,108 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: I have a turtle named "potter", reply single "ok" if you understand. - - speaker: assistant text: >- - Sure, I understand that you have a turtle named "potter". Just - to confirm, is there anything specific you would like me to - help you with related to your turtle or coding that you would - like to get started on? Otherwise, I'm here to assist you with - any questions or problems you might have about coding. If you - have any questions or need help with something, feel free to - ask! + Codebase context from file src/squirrel.ts: + ```typescript - For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + /** + * Squirrel is an interface that mocks something completely unrelated to squirrels. + * It is related to the implementation of precise code navigation in Sourcegraph. + */ + export interface Squirrel {} + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/multiple-selections.ts: + ```typescript + function outer() { + /* SELECTION_START */ + return function inner() {} + /* SELECTION_END */ + } - If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + /* SELECTION_2_START */ + function anotherFunction() {} + /* SELECTION_2_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/Heading.tsx: + ```typescript + import React = require("react"); + interface HeadingProps { + text: string; + level?: number; + } - In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + /* CURSOR */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); + + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

                Messages

                +
                  + {messages.map((message) => ( +
                • {message.text}
                • ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: >- + My selected code from codebase file + src/multiple-selections.ts:2-4: + ``` - I hope this helps. Do you have any questions for me? + return function inner() {} + ``` + - speaker: assistant + text: Ok. - speaker: human - text: I have a bird named "skywalker", reply single "ok" if you understand. + text: >- + You have access to the provided codebase context. + + + Question: What is the name of the function that I have selected? Only answer with the name of the function, nothing else model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -3305,32 +3283,27 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 14761 + bodySize: 282 content: mimeType: text/event-stream - size: 14761 - text: >+ + size: 282 + text: |+ event: completion - - data: {"completion":"I understand that you have a bird named \"skywalker\". It's always fun to have pets and give them unique names! Do you have any questions or need help with something related to coding or your pet bird? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} - + data: {"completion":"`inner`","stopReason":"stop"} event: done - data: {} cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:49 GMT + value: Thu, 04 Jul 2024 19:08:12 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive - - name: retry-after - value: "92" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -3348,12 +3321,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1405 + headersSize: 1299 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:48.988Z + startedDateTime: 2024-07-04T19:08:12.388Z time: 0 timings: blocked: -1 @@ -3363,11 +3336,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 98f2884871b118d4b9b09e5be5779896 + - _id: 4452e47fe6f7cf5a8f04c1260f422469 _order: 0 cache: {} request: - bodySize: 3143 + bodySize: 1717 cookies: [] headers: - name: content-type @@ -3376,75 +3349,71 @@ log: value: gzip;q=0 - name: authorization value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-a732fc4df74e86a9dec21f1d38a91822-6deb1c4425608122-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 401 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - 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: I have a turtle named "potter", reply single "ok" if you understand. - - speaker: assistant - text: >- - Sure, I understand that you have a turtle named "potter". Just - to confirm, is there anything specific you would like me to - help you with related to your turtle or coding that you would - like to get started on? Otherwise, I'm here to assist you with - any questions or problems you might have about coding. If you - have any questions or need help with something, feel free to - ask! - - - For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - - - If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. - - - In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! - - - I hope this helps. Do you have any questions for me? + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d + - name: user-agent + value: defaultClient / v1 + - name: traceparent + value: 00-d4291d2f1d191dfdc96d9000367179c4-737bbd0841b05104-01 + - name: connection + value: keep-alive + - name: host + value: sourcegraph.com + headersSize: 401 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json + params: [] + textJSON: + maxTokensToSample: 4000 + messages: - speaker: human - text: I have a bird named "skywalker", reply single "ok" if you understand. + text: You are Cody, an AI coding assistant from Sourcegraph. - speaker: assistant - text: >- - I understand that you have a bird named "skywalker". It's - always fun to have pets and give them unique names! Do you - have any questions or need help with something related to - coding or your pet bird? I'm here to help with any questions - or problems you might have. Just let me know what you'd like - to talk about. - - - If you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - - - If you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about. - + text: I am Cody, an AI coding assistant from Sourcegraph. + - speaker: human + text: > + Codebase context from file path src/animal.ts: /* + SELECTION_START */ - In the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey! + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + - speaker: assistant + text: Ok. + - speaker: human + text: |- + My selected code from codebase file src/animal.ts:1-6: + ``` - I hope this helps. Do you have any questions for me? + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + ``` + - speaker: assistant + text: Ok. - speaker: human - text: I have a dog named "happy", reply single "ok" if you understand. + text: "Explain what @src/animal.ts:1-6 ( @src/animal.ts ) does in simple terms. + Assume the audience is a beginner programmer who has just + learned the language features and basic syntax. Focus on + explaining: 1) The purpose of the code 2) What input(s) it + takes 3) What output(s) it produces 4) How it achieves its + purpose through the logic and algorithm. 5) Any important + logic flows or data transformations happening. Use simple + language a beginner could understand. Include enough detail to + give a full picture of what the code aims to accomplish + without getting too technical. Format the explanation in + coherent paragraphs, using proper punctuation and grammar. + Write the explanation assuming no prior context about the code + is known. Do not make assumptions about variables or functions + not shown in the shared code. Start the answer with the name + of the code that is being explained." model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -3456,14 +3425,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 10973 + bodySize: 43730 content: mimeType: text/event-stream - size: 10973 + size: 43730 text: >+ event: completion - data: {"completion":"I understand that you have a dog named \"happy\". Dogs are great companions and it's always fun to give them unique names. Do you have any questions or need help with something related to coding or your dog? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or dogs, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about dogs: Did you know that dogs are able to understand and respond to a wide range of words and commands? Some dogs are even able to learn hundreds of words and commands!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} + data: {"completion":"Sure, I'd be happy to explain.\n\nThe code you've shared is an interface called \"Animal\" from a TypeScript file called \"animal.ts\". An interface is like a blueprint for objects that defines what properties and methods an object should have. In this case, the Animal interface defines an object with three properties: \"name\", \"makeAnimalSound\", and \"isMammal\".\n\n1. The purpose of the code is to define the structure of an object that represents a generic animal in a program. The Animal interface specifies that any object that claims to be an animal should have a name, a method for making an animal sound, and a boolean property that indicates if the animal is a mammal.\n2. The interface doesn't take any inputs, as it only defines a structure. The inputs and outputs are defined by the objects that will implement this interface.\n3. Again, the interface itself doesn't produce any outputs, but it enables the creation of objects that have a specific structure, which is useful for defining and enforcing consistency and expectations in your code.\n4. The interface achieves its purpose by specifying the Required properties and methods that an object needs to have. The code states that the Animal interface must have a \"name\" property of type string, a \"makeAnimalSound\" method that returns a string, and an \"isMammal\" property of type boolean.\n5. The important logic flows or data transformations in this code are the definitions of the \"makeAnimalSound\" method and the \"isMammal\" property. These are not defined in the code you shared, but they are required to be implemented by whatever object uses this Animal interface. The \"makeAnimalSound\" method is expected to produce a sound that an animal makes, and the \"isMammal\" property is expected to be a boolean value that indicates whether the animal is a mammal. By requiring the implementation of these methods and properties, the Animal interface enables the creation of consistent, predictable animal objects in your code.\n\nIn summary, the Animal interface is a blueprint for animal objects that defines what properties and methods they should have, ensuring consistency and predictability. It doesn't take any inputs or produce any outputs, but it enables the creation of objects that have a specific structure.","stopReason":"stop"} event: done @@ -3473,15 +3442,13 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:51 GMT + value: Thu, 04 Jul 2024 19:08:13 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive - - name: retry-after - value: "91" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -3499,12 +3466,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1405 + headersSize: 1299 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:50.412Z + startedDateTime: 2024-07-04T19:08:12.973Z time: 0 timings: blocked: -1 @@ -3514,11 +3481,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: e314fb6c9f93ccee2363909a66529b07 + - _id: 76444b41b00f1213eafd950ad06efa7a _order: 0 cache: {} request: - bodySize: 1685 + bodySize: 2593 cookies: [] headers: - name: content-type @@ -3531,7 +3498,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-350e6487be7c211d20936b5717396f13-0d4d2e919924abb4-01 + value: 00-35e4ecdef8af3ee5ee512046eee0a9f0-b26c1b45479d5141-01 - name: connection value: keep-alive - name: host @@ -3550,30 +3517,69 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: I have a turtle named "potter", reply single "ok" if you understand. - - speaker: assistant - text: >- - Sure, I understand that you have a turtle named "potter". Just - to confirm, is there anything specific you would like me to - help you with related to your turtle or coding that you would - like to get started on? Otherwise, I'm here to assist you with - any questions or problems you might have about coding. If you - have any questions or need help with something, feel free to - ask! - + text: > + Codebase context from file path src/example.test.ts: import { + expect } from 'vitest' - For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + import { it } from 'vitest' + import { describe } from 'vitest' - If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + describe('test block', () => { + it('does 1', () => { + expect(true).toBe(true) + }) - In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + it('does 2', () => { + expect(true).toBe(true) + }) + it('does something else', () => { + // This line will error due to incorrect usage of `performance.now` + const startTime = performance.now(/* CURSOR */) + }) + }) + - speaker: assistant + text: Ok. + - speaker: human + text: |- + My selected code from codebase file src/animal.ts:1-6: + ``` - I hope this helps. Do you have any questions for me? + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + ``` + - speaker: assistant + text: Ok. - speaker: human - text: I have a tiger named "zorro", reply single "ok" if you understand + text: Review the shared code context and configurations to identify the test + framework and libraries in use. Then, generate a suite of + multiple unit tests for the functions in using the + detected test framework and libraries. Be sure to import the + function being tested. Follow the same patterns as any shared + context. Only add packages, imports, dependencies, and + assertions if they are used in the shared code. Pay attention + to the file path of each shared context to see if test for + already exists. If one exists, focus on generating + new unit tests for uncovered cases. If none are detected, + import common unit test libraries for {languageName}. Focus on + validating key functionality with simple and complete + assertions. Only include mocks if one is detected in the + shared code. Before writing the tests, identify which test + libraries and frameworks to import, e.g. 'No new imports + needed - using existing libs' or 'Importing test framework + that matches shared context usage' or 'Importing the defined + framework', etc. Then briefly summarize test coverage and any + limitations. At the end, enclose the full completed code for + the new unit tests, including all necessary imports, in a + single markdown codeblock. No fragments or TODO. The new tests + should validate expected functionality and cover edge cases + for with all required imports, including importing + the function being tested. Do not repeat existing tests. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -3585,14 +3591,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 22370 + bodySize: 46508 content: mimeType: text/event-stream - size: 22370 + size: 46508 text: >+ event: completion - data: {"completion":"I understand that you have a tiger named \"zorro\". Is there anything specific you would like to ask or discuss about your tiger or related to coding that you would like me to help with?\n\nAs a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges.\n\nIf you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything.\n\nIf you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\nI hope this helps. Do you have any questions or concerns for me?\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} + data: {"completion":"Based on the code context and configurations provided in the examples, it appears that the Vitest testing framework is being used.\n\nFor the `Animal` interface that has been shared, I will generate some tests to validate the required functionality.\n\nTo write the tests, I will import `describe`, `test`, and `expect` from the Vitest framework, along with the `Animal` interface from the file at `src/animal.ts`.\n\nHere is a suite of tests that I recommend adding to the project to ensure the correct functionality of the `Animal` interface:\n```typescript\nimport { describe, test, expect } from 'vitest'\nimport { Animal } from '../animal'\n\ndescribe('Animal interface', () =\u003e {\n test('has a name property that is a string', () =\u003e {\n const animal: Animal = {\n name: 'Dog',\n makeAnimalSound: () =\u003e 'Bark',\n isMammal: true\n }\n\n expect(animal.name).toBeTypeOf('string')\n })\n\n test('has a makeAnimalSound function that returns a string', () =\u003e {\n const animal: Animal = {\n name: 'Dog',\n makeAnimalSound: () =\u003e 'Bark',\n isMammal: true\n }\n\n expect(animal.makeAnimalSound()).toBeTypeOf('string')\n })\n\n test('has a boolean property isMammal', () =\u003e {\n const animal: Animal = {\n name: 'Dog',\n makeAnimalSound: () =\u003e 'Bark',\n isMammal: true\n }\n\n expect(animal.isMammal).toBeTypeOf('boolean')\n })\n\n test('throws an error when the makeAnimalSound function is not defined', () =\u003e {\n const animal: Animal = {\n name: 'Dog',\n isMammal: true\n }\n\n expect(() =\u003e animal.makeAnimalSound()).toThrowError()\n })\n\n test('throws an error when the name property is not defined', () =\u003e {\n const animal: Animal = {\n makeAnimalSound: () =\u003e 'Bark',\n isMammal: true\n }\n\n expect(() =\u003e (animal as { name: string })).toThrowError()\n })\n})\n```\nThis test suite covers the primary functionality of the `Animal` interface and checks that the required `name` and `isMammal` properties are defined and that the `makeAnimalSound` function returns a string.\n\nI hope this helps!","stopReason":"stop"} event: done @@ -3602,15 +3608,13 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:52 GMT + value: Thu, 04 Jul 2024 19:08:16 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive - - name: retry-after - value: "90" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -3628,12 +3632,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1405 + headersSize: 1299 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:51.605Z + startedDateTime: 2024-07-04T19:08:15.365Z time: 0 timings: blocked: -1 @@ -3643,11 +3647,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 7c1d096239c8d170c18db5501e43e433 + - _id: f81afbdd87bad58d33d5e94a94056470 _order: 0 cache: {} request: - bodySize: 3463 + bodySize: 1513 cookies: [] headers: - name: content-type @@ -3660,7 +3664,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-aa645675e25db20a958f4bbb5b4d9659-e7951db609ddd9a9-01 + value: 00-2dab55b0b15cfe5d5c728b8172c7293f-6b93b947af2ffe79-01 - name: connection value: keep-alive - name: host @@ -3679,53 +3683,45 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: I have a turtle named "potter", reply single "ok" if you understand. - - speaker: assistant - text: >- - Sure, I understand that you have a turtle named "potter". Just - to confirm, is there anything specific you would like me to - help you with related to your turtle or coding that you would - like to get started on? Otherwise, I'm here to assist you with - any questions or problems you might have about coding. If you - have any questions or need help with something, feel free to - ask! - - - For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - - - If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. - - - In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + text: > + Codebase context from file path src/animal.ts: /* + SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } - I hope this helps. Do you have any questions for me? - - speaker: human - text: I have a tiger named "zorro", reply single "ok" if you understand + /* SELECTION_END */ - speaker: assistant - text: >- - I understand that you have a tiger named "zorro". Is there - anything specific you would like to ask or discuss about your - tiger or related to coding that you would like me to help - with? - - - As a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges. - - - If you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything. - - - If you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about. - - - I hope this helps. Do you have any questions or concerns for me? - + text: Ok. + - speaker: human + text: |- + My selected code from codebase file src/animal.ts:1-6: + ``` - (By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!) + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + ``` + - speaker: assistant + text: Ok. - speaker: human - text: What pets do I have? + text: Please review and analyze @src/animal.ts:1-6 ( @src/animal.ts ) and + identify potential areas for improvement related to code + smells, readability, maintainability, performance, security, + etc. Do not list issues already addressed in the given code. + Focus on providing up to 5 constructive suggestions that could + make the code more robust, efficient, or align with best + practices. For each suggestion, provide a brief explanation of + the potential benefits. After listing any recommendations, + summarize if you found notable opportunities to enhance the + code quality overall or if the code generally follows sound + design principles. If no issues found, reply 'There are no + errors.' model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -3737,14 +3733,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 12007 + bodySize: 33591 content: mimeType: text/event-stream - size: 12007 + size: 33591 text: >+ event: completion - data: {"completion":"Based on the information you have provided, it appears that you have a turtle named \"potter\" and a tiger named \"zorro\". I am a machine learning model, and my ability to accurately and comprehensively understand and recall information about a user is limited. I am intended to be used as a coding assistant, and I am not able to access or retrieve personal information about users unless it has been explicitly shared with me in the course of our conversation.\n\nI hope this helps clarify my capabilities and limitations. Do you have any questions or concerns about using me as a coding assistant, or would you like me to help you with any coding-related questions or problems you might have? I'm here to help with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} + data: {"completion":"Based on the examination of your TypeScript code at `src/animal.ts:1-6`, I found some potential improvements:\n\n1. Use consistent naming conventions:\n Rename the `isMammal` property to `isMammal`, conforming to PascalCase, which TypeScript recommends for interface properties.\n\n Benefit: Improves readability and consistency in the codebase.\n\n2. Add the missing semicolons:\n Add semicolons to the end of the `name` and `makeAnimalSound` lines, as they ensure that your code behaves consistently and avoids bugs related to automatic semicolon insertion.\n\n Benefit: Ensures predictability and robustness in code execution.\n\n3. Restrict the Animal interface:\n Define the `makeAnimalSound()` method with an abstract keyword or a type requiring a specific implementation (i.e., a function or a class).\n\n Benefit: Provides better type safety and enforces consistent behavior.\n\n4. Include a description or documentation:\n Add a brief description of the `Animal` interface to help others understand its purpose.\n\n Benefit: Improves maintainability and readability for other developers.\n\n5. Encapsulate related properties and methods in a class or module:\n If you're dealing with a class or module that has many interfaces or extensive use cases, you may consider encapsulating the `Animal` interface in a class or a specific module.\n\n Benefit: Enhances encapsulation and modularization, also making your code more manageable.\n\n---\n\nIn summary, the provided code adheres to fundamental design principles, but can be improved in specific areas for better readability, maintainability, and alignment with best practices in TypeScript. Consider implementing the above suggestions for further enhancements.","stopReason":"stop"} event: done @@ -3754,15 +3750,13 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:54 GMT + value: Thu, 04 Jul 2024 19:08:18 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive - - name: retry-after - value: "88" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -3780,12 +3774,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1405 + headersSize: 1299 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:53.211Z + startedDateTime: 2024-07-04T19:08:17.838Z time: 0 timings: blocked: -1 diff --git a/agent/src/index.test.ts b/agent/src/index.test.ts index e2ccb14dee4..3742cfac01c 100644 --- a/agent/src/index.test.ts +++ b/agent/src/index.test.ts @@ -703,23 +703,17 @@ describe('Agent', () => { const lastMessage = await client.firstNonEmptyTranscript(id) expect(trimEndOfLine(lastMessage.messages.at(-1)?.text ?? '')).toMatchInlineSnapshot( ` - "The code snippet \`src/animal.ts:1-6\` defines an interface named \`Animal\` in TypeScript. An interface is a way to define a contract or shape for an object. It specifies what properties and methods an object should have, but it does not provide any implementation details. + "Sure, I'd be happy to explain. - The \`Animal\` interface has three properties: + The code you've shared is an interface called "Animal" from a TypeScript file called "animal.ts". An interface is like a blueprint for objects that defines what properties and methods an object should have. In this case, the Animal interface defines an object with three properties: "name", "makeAnimalSound", and "isMammal". - 1. \`name\`: This property is a string that likely represents the name of the animal. - 2. \`makeAnimalSound()\`: This is a method that returns a string. It is expected to return the sound that the animal makes when called. - 3. \`isMammal\`: This is a boolean property that indicates whether the animal is a mammal or not. + 1. The purpose of the code is to define the structure of an object that represents a generic animal in a program. The Animal interface specifies that any object that claims to be an animal should have a name, a method for making an animal sound, and a boolean property that indicates if the animal is a mammal. + 2. The interface doesn't take any inputs, as it only defines a structure. The inputs and outputs are defined by the objects that will implement this interface. + 3. Again, the interface itself doesn't produce any outputs, but it enables the creation of objects that have a specific structure, which is useful for defining and enforcing consistency and expectations in your code. + 4. The interface achieves its purpose by specifying the Required properties and methods that an object needs to have. The code states that the Animal interface must have a "name" property of type string, a "makeAnimalSound" method that returns a string, and an "isMammal" property of type boolean. + 5. The important logic flows or data transformations in this code are the definitions of the "makeAnimalSound" method and the "isMammal" property. These are not defined in the code you shared, but they are required to be implemented by whatever object uses this Animal interface. The "makeAnimalSound" method is expected to produce a sound that an animal makes, and the "isMammal" property is expected to be a boolean value that indicates whether the animal is a mammal. By requiring the implementation of these methods and properties, the Animal interface enables the creation of consistent, predictable animal objects in your code. - The purpose of this code is to serve as a blueprint or a contract for any object that represents an animal in the application. It defines the required properties and methods that an animal object should have. - - This interface does not take any inputs directly. Instead, it serves as a guideline for creating objects that conform to the \`Animal\` interface. When creating an object that represents an animal, the object must have a \`name\` property (a string), a \`makeAnimalSound()\` method (which returns a string), and an \`isMammal\` property (a boolean). - - The interface itself does not produce any output. It is a contract that other parts of the code can use to ensure that objects representing animals have the required properties and methods. - - The purpose of the \`Animal\` interface is achieved by defining the shape of an animal object. Any object that conforms to this interface will have the specified properties and methods, making it easier to work with animals consistently throughout the codebase. - - It's important to note that this code snippet alone does not contain any logic or algorithms. It merely defines the structure of an animal object, which can be used later in the application to create instances of animals and interact with them." + In summary, the Animal interface is a blueprint for animal objects that defines what properties and methods they should have, ensuring consistency and predictability. It doesn't take any inputs or produce any outputs, but it enables the creation of objects that have a specific structure." `, explainPollyError ) @@ -734,73 +728,70 @@ describe('Agent', () => { const lastMessage = await client.firstNonEmptyTranscript(id) expect(trimEndOfLine(lastMessage.messages.at(-1)?.text ?? '')).toMatchInlineSnapshot( ` - "Based on the provided code context, the test framework being used is Vitest. No new imports are needed - I will be using the existing Vitest imports. - - The \`Animal\` interface represents an animal with properties like \`name\` (string), \`makeAnimalSound\` (function that returns a string), and \`isMammal\` (boolean). + "Based on the code context and configurations provided in the examples, it appears that the Vitest testing framework is being used. - To test this interface, I will create an implementation of the \`Animal\` interface and write unit tests to validate its behavior. + For the \`Animal\` interface that has been shared, I will generate some tests to validate the required functionality. - Here's a suite of unit tests for the \`Animal\` interface: + To write the tests, I will import \`describe\`, \`test\`, and \`expect\` from the Vitest framework, along with the \`Animal\` interface from the file at \`src/animal.ts\`. + Here is a suite of tests that I recommend adding to the project to ensure the correct functionality of the \`Animal\` interface: \`\`\`typescript - import { describe, it, expect } from 'vitest' + import { describe, test, expect } from 'vitest' + import { Animal } from '../animal' + + describe('Animal interface', () => { + test('has a name property that is a string', () => { + const animal: Animal = { + name: 'Dog', + makeAnimalSound: () => 'Bark', + isMammal: true + } - // Implementation of the Animal interface - class Dog implements Animal { - name: string - isMammal: boolean + expect(animal.name).toBeTypeOf('string') + }) - constructor(name: string) { - this.name = name - this.isMammal = true - } + test('has a makeAnimalSound function that returns a string', () => { + const animal: Animal = { + name: 'Dog', + makeAnimalSound: () => 'Bark', + isMammal: true + } - makeAnimalSound(): string { - return 'Woof!' - } - } + expect(animal.makeAnimalSound()).toBeTypeOf('string') + }) - describe('Animal', () => { - describe('Dog', () => { - const dog = new Dog('Buddy') + test('has a boolean property isMammal', () => { + const animal: Animal = { + name: 'Dog', + makeAnimalSound: () => 'Bark', + isMammal: true + } - it('should have a name', () => { - expect(dog.name).toBe('Buddy') + expect(animal.isMammal).toBeTypeOf('boolean') }) - it('should be a mammal', () => { - expect(dog.isMammal).toBe(true) - }) + test('throws an error when the makeAnimalSound function is not defined', () => { + const animal: Animal = { + name: 'Dog', + isMammal: true + } - it('should make a sound', () => { - expect(dog.makeAnimalSound()).toBe('Woof!') + expect(() => animal.makeAnimalSound()).toThrowError() }) - }) - describe('Edge cases', () => { - it('should handle empty name', () => { - const dog = new Dog('') - expect(dog.name).toBe('') - }) + test('throws an error when the name property is not defined', () => { + const animal: Animal = { + makeAnimalSound: () => 'Bark', + isMammal: true + } - it('should handle non-mammal animal', () => { - const bird = { name: 'Tweety', makeAnimalSound: () => 'Chirp!', isMammal: false } - expect(bird.isMammal).toBe(false) - expect(bird.makeAnimalSound()).toBe('Chirp!') + expect(() => (animal as { name: string })).toThrowError() }) - }) }) \`\`\` + This test suite covers the primary functionality of the \`Animal\` interface and checks that the required \`name\` and \`isMammal\` properties are defined and that the \`makeAnimalSound\` function returns a string. - This test suite covers the following: - - 1. Validating the \`name\` property of the \`Animal\` implementation. - 2. Validating the \`isMammal\` property of the \`Animal\` implementation. - 3. Validating the \`makeAnimalSound\` method of the \`Animal\` implementation. - 4. Edge case: handling an empty name for the \`Animal\` implementation. - 5. Edge case: handling a non-mammal \`Animal\` implementation. - - The tests ensure that the \`Animal\` interface implementation behaves as expected and covers edge cases like empty names and non-mammal animals." + I hope this helps!" `, explainPollyError ) @@ -815,29 +806,36 @@ describe('Agent', () => { expect(trimEndOfLine(lastMessage.messages.at(-1)?.text ?? '')).toMatchInlineSnapshot( ` - "Based on the provided code snippet, here are a few suggestions for potential improvements: + "Based on the examination of your TypeScript code at \`src/animal.ts:1-6\`, I found some potential improvements: - 1. **Use descriptive interface name**: The interface name \`Animal\` is quite generic and may not provide enough context or clarity, especially in larger codebases. Consider using a more descriptive name that better represents the purpose or domain of the interface, such as \`AnimalEntity\` or \`AnimalModel\`. + 1. Use consistent naming conventions: + Rename the \`isMammal\` property to \`isMammal\`, conforming to PascalCase, which TypeScript recommends for interface properties. - Potential benefit: A more descriptive name can improve code readability and make it easier to understand the intent and usage of the interface. + Benefit: Improves readability and consistency in the codebase. - 2. **Consider adding documentation**: While the code itself is relatively straightforward, adding documentation in the form of comments or utilizing TypeScript's built-in documentation support (e.g., JSDoc) can enhance code maintainability and make it easier for other developers to understand the purpose and expected behavior of the interface. + 2. Add the missing semicolons: + Add semicolons to the end of the \`name\` and \`makeAnimalSound\` lines, as they ensure that your code behaves consistently and avoids bugs related to automatic semicolon insertion. - Potential benefit: Well-documented code is easier to maintain, understand, and extend, especially in collaborative environments or when revisiting the codebase after some time. + Benefit: Ensures predictability and robustness in code execution. - 3. **Implement a base class or interface for common properties**: If there are other interfaces or classes related to animals or living beings in your codebase, it might be worth considering implementing a base class or interface to share common properties and methods. This can help reduce code duplication and promote code reusability. + 3. Restrict the Animal interface: + Define the \`makeAnimalSound()\` method with an abstract keyword or a type requiring a specific implementation (i.e., a function or a class). - Potential benefit: By extracting common properties and methods into a shared base, you can reduce code duplication, improve maintainability, and make it easier to apply changes consistently across related types. + Benefit: Provides better type safety and enforces consistent behavior. - 4. **Consider using TypeScript's built-in utility types**: TypeScript provides several built-in utility types, such as \`Readonly\` and \`Required\`, which can be used to enforce immutability or ensure that all properties are required. These utility types can help catch potential bugs at compile-time and improve code correctness. + 4. Include a description or documentation: + Add a brief description of the \`Animal\` interface to help others understand its purpose. - Potential benefit: Utilizing TypeScript's built-in utility types can enhance type safety, catch potential bugs earlier, and promote better code quality. + Benefit: Improves maintainability and readability for other developers. - 5. **Review the naming conventions**: While the property names \`name\` and \`isMammal\` follow common naming conventions, the method name \`makeAnimalSound\` could be more concise and descriptive. Consider renaming it to something like \`makeSound\` or \`getSound\`. + 5. Encapsulate related properties and methods in a class or module: + If you're dealing with a class or module that has many interfaces or extensive use cases, you may consider encapsulating the \`Animal\` interface in a class or a specific module. - Potential benefit: Consistent and descriptive naming conventions can improve code readability and maintainability, making it easier for developers to understand and work with the codebase. + Benefit: Enhances encapsulation and modularization, also making your code more manageable. - Overall, while the provided code snippet is relatively simple and follows some good design principles, there are opportunities for improvement, primarily in the areas of documentation, code organization, and naming conventions. By addressing these suggestions, you can enhance the code's readability, maintainability, and overall quality." + --- + + In summary, the provided code adheres to fundamental design principles, but can be improved in specific areas for better readability, maintainability, and alignment with best practices in TypeScript. Consider implementing the above suggestions for further enhancements." `, explainPollyError ) @@ -994,7 +992,7 @@ describe('Agent', () => { it('chat/submitMessage', async () => { const lastMessage = await demoEnterpriseClient.sendSingleMessageToNewChat('Reply with "Yes"') expect(lastMessage?.text?.trim()).toStrictEqual('Yes') - }, 20_000) + }, 20_000_000) // Skip because it consistently fails with: // Error: Test timed out in 20000ms. diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index ab08183bd4f..227ddae59b3 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -222,7 +222,7 @@ export class ModelsService { */ private static localModels: Model[] = [] - private static defaultModels: Map = new Map() + private static defaultModels: Map = new Map() private static storage: Storage | undefined @@ -283,17 +283,17 @@ export class ModelsService { } public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { + const models = ModelsService.getModelsByType(type) + const firstModelUserCanUse = models.find(m => ModelsService.canUserUseModel(authStatus, m)) if (!authStatus.authenticated) { - throw new Error('You are not authenticated') + return firstModelUserCanUse } const current = ModelsService.defaultModels.get(type) - if (current) return current - - const models = ModelsService.getModelsByType(type) + if (current) return models.find(m => m.model === current) // Free users can only use the default model if (isFreeUser(authStatus) || !ModelsService.storage) { - return models.find(m => ModelsService.canUserUseModel(authStatus, m)) + return firstModelUserCanUse } // Check for the last selected model @@ -321,15 +321,18 @@ export class ModelsService { } public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { - model = ModelsService.resolveModel(model) - ModelsService.defaultModels.set(type, model) + const modelId = typeof model === 'string' ? model : model.model + ModelsService.defaultModels.set(type, modelId) // If we have persistent storage set, write it there - await ModelsService.storage?.set(ModelsService.storageKeys[type], model.model) + await ModelsService.storage?.set(ModelsService.storageKeys[type], modelId) } public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { - model = ModelsService.resolveModel(model) - const tier = Model.tier(model) + const resolved = ModelsService.resolveModel(model) + if (!resolved) { + return false + } + const tier = Model.tier(resolved) if (isEnterpriseUser(status)) { return tier === 'enterprise' } @@ -342,15 +345,11 @@ export class ModelsService { return false } - private static resolveModel(modelID: Model | string): Model { + private static resolveModel(modelID: Model | string): Model | undefined { if (typeof modelID !== 'string') { return modelID } - const model = ModelsService.models.find(m => m.model === modelID) - if (!model) { - throw new Error(`Unknown model: ${modelID}`) - } - return model + return ModelsService.models.find(m => m.model === modelID) } /** From 34d53ba8e584f326287116143bbc604d1f80a424 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 4 Jul 2024 18:45:04 -0700 Subject: [PATCH 10/34] fixes for tests --- .gitignore | 1 + lib/shared/src/models/dotcom.ts | 2 +- lib/shared/src/models/index.ts | 16 ++++++---------- lib/shared/src/sourcegraph-api/rest/client.ts | 6 ++---- vscode/test/e2e/command-core.test.ts | 3 ++- vscode/webviews/App.tsx | 10 ++++------ 6 files changed, 16 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 3384fc1ae5f..e5e69c78b81 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ index.scip playwright playwright-report test-results +.vscode-test/ diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 4bacd5a53a4..2155fa13998 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -39,7 +39,7 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - tags: [ModelTag.Gateway, ModelTag.Balanced], + tags: [ModelTag.Gateway, ModelTag.Balanced, ModelTag.Free], }, { title: 'Claude 3.5 Sonnet', diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 227ddae59b3..2a125656cd9 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -285,17 +285,15 @@ export class ModelsService { public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { const models = ModelsService.getModelsByType(type) const firstModelUserCanUse = models.find(m => ModelsService.canUserUseModel(authStatus, m)) - if (!authStatus.authenticated) { + if (!authStatus.authenticated || isFreeUser(authStatus)) { return firstModelUserCanUse } const current = ModelsService.defaultModels.get(type) - if (current) return models.find(m => m.model === current) - - // Free users can only use the default model - if (isFreeUser(authStatus) || !ModelsService.storage) { - return firstModelUserCanUse + if (current) { + return models.find(m => m.model === current) || firstModelUserCanUse } + // Check for the last selected model const lastSelectedModelID = ModelsService.storage.get(ModelsService.storageKeys[type]) // TODO(jsm): Global migration should happen once in the activation @@ -339,10 +337,8 @@ export class ModelsService { if (isCodyProUser(status)) { return tier !== 'enterprise' } - if (isFreeUser(status)) { - return tier === 'free' - } - return false + + return tier === 'free' } private static resolveModel(modelID: Model | string): Model | undefined { diff --git a/lib/shared/src/sourcegraph-api/rest/client.ts b/lib/shared/src/sourcegraph-api/rest/client.ts index e7842281dd1..cda4303791b 100644 --- a/lib/shared/src/sourcegraph-api/rest/client.ts +++ b/lib/shared/src/sourcegraph-api/rest/client.ts @@ -62,10 +62,8 @@ export class RestClient { // // NOTE: This API endpoint hasn't shippeted yet, and probably won't work for you. // Also, the URL definitely will change. - let serverSideConfig: any - try { - serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') - } catch { + let serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') + if (serverSideConfig instanceof Error) { serverSideConfig = testModels } diff --git a/vscode/test/e2e/command-core.test.ts b/vscode/test/e2e/command-core.test.ts index 4ec77c16d67..7e15388bfb7 100644 --- a/vscode/test/e2e/command-core.test.ts +++ b/vscode/test/e2e/command-core.test.ts @@ -5,6 +5,7 @@ import { chatInputMentions, contextCellItems, expectContextCellCounts, + focusSidebar, getContextCell, openContextCell, sidebarExplorer, @@ -63,7 +64,7 @@ test.extend({ await page.getByRole('tab', { name: 'index.html' }).hover() // Bring the cody sidebar to the foreground - await page.getByRole('tab', { name: 'Cody', exact: true }).locator('a').click() + await focusSidebar(page) await page.getByText('Explain Code').hover() await page.getByText('Explain Code').click() diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index 141cd2fcb9e..d03ef698315 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -10,6 +10,7 @@ import { Model, PromptString, type SerializedChatTranscript, + isCodyProUser, isEnterpriseUser, } from '@sourcegraph/cody-shared' import type { UserAccountInfo } from './Chat' @@ -102,7 +103,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc setConfig(message.config) setAuthStatus(message.authStatus) setUserAccountInfo({ - isCodyProUser: !message.authStatus.userCanUpgrade, + isCodyProUser: isCodyProUser(message.authStatus), // Receive this value from the extension backend to make it work // with E2E tests where change the DOTCOM_URL via the env variable TESTING_DOTCOM_URL. isDotComUser: message.authStatus.isDotCom, @@ -145,7 +146,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc info => info && { ...info, - isOldStyleEnterprise: + isOldStyleEnterpriseUser: !info.isDotComUser && !message.models.some(Model.isNewStyleEnterprise), } @@ -214,10 +215,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc command: 'chatModel', model: selected.model, }) - const updatedChatModels = chatModels.map(m => - m.model === selected.model ? { ...m, default: true } : { ...m, default: false } - ) - setChatModels(updatedChatModels) + setChatModels([selected].concat(chatModels.filter(m => m.model !== selected.model))) }, [chatModels, vscodeAPI] ) From 3333b8d472db75285c73291840feb15848e462a3 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 4 Jul 2024 19:22:19 -0700 Subject: [PATCH 11/34] fixed type error --- lib/shared/src/models/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 2a125656cd9..6c0fb3bc75f 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -252,6 +252,7 @@ export class ModelsService { * NOTE: private instances can only support 1 provider ATM. */ public static setModels(models: Model[]): void { + console.trace('MODELS ARE: ', models) ModelsService.primaryModels = models } @@ -293,9 +294,8 @@ export class ModelsService { return models.find(m => m.model === current) || firstModelUserCanUse } - // Check for the last selected model - const lastSelectedModelID = ModelsService.storage.get(ModelsService.storageKeys[type]) + const lastSelectedModelID = ModelsService.storage?.get(ModelsService.storageKeys[type]) // TODO(jsm): Global migration should happen once in the activation // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) From db80ff8f16e8b5de12d19d1242b6291e26eb9710 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 4 Jul 2024 19:22:19 -0700 Subject: [PATCH 12/34] fixed type error --- agent/src/index.test.ts | 2 +- lib/shared/src/models/index.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/agent/src/index.test.ts b/agent/src/index.test.ts index 3742cfac01c..a7ef487b933 100644 --- a/agent/src/index.test.ts +++ b/agent/src/index.test.ts @@ -992,7 +992,7 @@ describe('Agent', () => { it('chat/submitMessage', async () => { const lastMessage = await demoEnterpriseClient.sendSingleMessageToNewChat('Reply with "Yes"') expect(lastMessage?.text?.trim()).toStrictEqual('Yes') - }, 20_000_000) + }, 20_000) // Skip because it consistently fails with: // Error: Test timed out in 20000ms. diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 2a125656cd9..40e8d226906 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -293,9 +293,8 @@ export class ModelsService { return models.find(m => m.model === current) || firstModelUserCanUse } - // Check for the last selected model - const lastSelectedModelID = ModelsService.storage.get(ModelsService.storageKeys[type]) + const lastSelectedModelID = ModelsService.storage?.get(ModelsService.storageKeys[type]) // TODO(jsm): Global migration should happen once in the activation // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) From bd7d289e67ae58c65d39d2764f7a610381b7a8b4 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 4 Jul 2024 19:24:52 -0700 Subject: [PATCH 13/34] removed console --- lib/shared/src/models/index.ts | 390 --------------------------------- 1 file changed, 390 deletions(-) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 6c0fb3bc75f..8b137891791 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1,391 +1 @@ -import { type AuthStatus, isCodyProUser, isEnterpriseUser, isFreeUser } from '../auth/types' -import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' -import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' -import { ModelTag } from './tags' -import { type ChatModel, type EditModel, type ModelContextWindow, ModelUsage } from './types' -import { getModelInfo } from './utils' -export type ModelId = string -export type ApiVersionId = string -export type ProviderId = string - -export type ModelRef = `${ProviderId}::${ApiVersionId}::${ModelId}` - -export type ModelCapability = 'chat' | 'autocomplete' -export type ModelCategory = 'accuracy' | 'balanced' | 'speed' -export type ModelStatus = 'experimental' | 'beta' | 'stable' | 'deprecated' -export type ModelTier = 'free' | 'pro' | 'enterprise' - -export interface ContextWindow { - maxInputTokens: number - maxOutputTokens: number -} - -export interface ServerModel { - modelRef: ModelRef - displayName: string - modelName: string - capabilities: ModelCapability[] - category: ModelCategory - status: ModelStatus - tier: ModelTier - - contextWindow: ContextWindow - - clientSideConfig?: unknown -} - -/** - * Model describes an LLM model and its capabilities. - */ -export class Model { - /** - * The model id that includes the provider name & the model name, - * e.g. "anthropic/claude-3-sonnet-20240229" - * - * TODO(PRIME-282): Replace this with a `ModelRef` instance and introduce a separate - * "modelId" that is distinct from the "modelName". (e.g. "claude-3-sonnet" vs. "claude-3-sonnet-20240229") - */ - public readonly model: string - /** - * The usage of the model, e.g. chat or edit. - */ - public readonly usage: ModelUsage[] - /** - * The default context window of the model reserved for Chat and Context. - * {@see TokenCounter on how the token usage is calculated.} - */ - public readonly contextWindow: ModelContextWindow - - /** - * The client-specific configuration for the model. - */ - public readonly clientSideConfig?: { - /** - * The API key for the model - */ - apiKey?: string - /** - * The API endpoint for the model - */ - apiEndpoint?: string - } - - // The name of the provider of the model, e.g. "Anthropic" - public provider: string - // The title of the model, e.g. "Claude 3 Sonnet" - public readonly title: string - /** - * The tags assigned for categorizing the model. - */ - public readonly tags: ModelTag[] = [] - - constructor({ - model, - usage, - contextWindow = { - input: CHAT_INPUT_TOKEN_BUDGET, - output: CHAT_OUTPUT_TOKEN_BUDGET, - }, - clientSideConfig, - tags = [], - provider, - title, - }: ModelParams) { - this.model = model - this.usage = usage - this.contextWindow = contextWindow - this.clientSideConfig = clientSideConfig - this.tags = tags - - const info = getModelInfo(model) - this.provider = provider ?? info.provider - this.title = title ?? info.title - } - - static fromApi({ - modelRef, - displayName, - capabilities, - category, - tier, - clientSideConfig, - contextWindow, - }: ServerModel) { - // BUG: There is data loss here and the potential for ambiguity. - // BUG: We are assuming the modelRef is valid, but it might not be. - const [providerId, _, modelId] = modelRef.split('::', 3) - - const categoryTag = ((): ModelTag => { - switch (category) { - case 'accuracy': - return ModelTag.Accuracy - case 'balanced': - return ModelTag.Balanced - case 'speed': - return ModelTag.Speed - } - })() - - const tierTag = ((): ModelTag => { - switch (tier) { - case 'free': - return ModelTag.Free - case 'pro': - return ModelTag.Pro - case 'enterprise': - return ModelTag.Enterprise - } - })() - - return new Model({ - model: modelId, - usage: capabilities.flatMap(capabilityToUsage), - contextWindow: { - input: contextWindow.maxInputTokens, - output: contextWindow.maxOutputTokens, - }, - // @ts-ignore - clientSideConfig: clientSideConfig, - tags: [categoryTag, tierTag], - provider: providerId, - title: displayName, - }) - } - - static isNewStyleEnterprise(model: Model): boolean { - return model.tags.includes(ModelTag.Enterprise) - } - - static tier(model: Model): ModelTier { - if (model.tags.includes(ModelTag.Free)) { - return 'free' - } - if (model.tags.includes(ModelTag.Pro)) { - return 'pro' - } - if (model.tags.includes(ModelTag.Enterprise)) { - return 'enterprise' - } - - return 'pro' - } - - static isCodyPro(model?: Model): boolean { - return Boolean(model?.tags.includes(ModelTag.Pro)) - } -} - -interface ModelParams { - model: string - usage: ModelUsage[] - contextWindow?: ModelContextWindow - clientSideConfig?: { - apiKey?: string - apiEndpoint?: string - } - tags?: ModelTag[] - provider?: string - title?: string -} - -/** - * ModelsService is the component responsible for keeping track of which models - * are supported on the backend, which ones are available based on the user's - * preferences, etc. - * - * TODO(PRIME-228): Update this type to be able to fetch the models from the - * Sourcegraph backend instead of being hard-coded. - * TODO(PRIME-283): Enable Cody Enterprise users to select which LLM model to - * used in the UI. (By having the relevant code paths just pull the models - * from this type.) - */ -export class ModelsService { - // Unused. Only to work around the linter complaining about a static-only class. - // When we are fetching data from the Sourcegraph backend, and relying on the - // current user's credentials, we'll need to turn this into a proper singleton - // with an initialization step on startup. - protected ModelsService() {} - - /** - * Get all the providers currently available to the user - */ - private static get models(): Model[] { - return ModelsService.primaryModels.concat(ModelsService.localModels) - } - /** - * Models available on the user's Sourcegraph instance. - */ - private static primaryModels: Model[] = [] - /** - * Models available from user's local instances, e.g. Ollama. - */ - private static localModels: Model[] = [] - - private static defaultModels: Map = new Map() - - private static storage: Storage | undefined - - private static storageKeys = { - [ModelUsage.Chat]: 'chat', - [ModelUsage.Edit]: 'editModel', - } - - public static setStorage(storage: Storage): void { - ModelsService.storage = storage - } - - public static async onConfigChange(): Promise { - try { - ModelsService.localModels = await fetchLocalOllamaModels() - } catch { - ModelsService.localModels = [] - } - } - - private static getModelsByType(usage: ModelUsage): Model[] { - return ModelsService.models.filter(model => model.usage.includes(usage)) - } - - /** - * Sets the primary models available to the user. - * NOTE: private instances can only support 1 provider ATM. - */ - public static setModels(models: Model[]): void { - console.trace('MODELS ARE: ', models) - ModelsService.primaryModels = models - } - - /** - * Add new models for use. - */ - public static addModels(models: Model[]): void { - const set = new Set(ModelsService.primaryModels) - for (const provider of models) { - set.add(provider) - } - ModelsService.primaryModels = Array.from(set) - } - - /** - * Gets the available models of the specified usage type, with the default model first. - * - * @param type - The usage type of the models to retrieve. - * @param authStatus - The authentication status of the user. - * @returns An array of models, with the default model first. - */ - public static getModels(type: ModelUsage, authStatus: AuthStatus): Model[] { - const models = ModelsService.getModelsByType(type) - const currentModel = ModelsService.getDefaultModel(type, authStatus) - if (!currentModel) { - return models - } - return [currentModel].concat(models.filter(m => m.model !== currentModel.model)) - } - - public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { - const models = ModelsService.getModelsByType(type) - const firstModelUserCanUse = models.find(m => ModelsService.canUserUseModel(authStatus, m)) - if (!authStatus.authenticated || isFreeUser(authStatus)) { - return firstModelUserCanUse - } - const current = ModelsService.defaultModels.get(type) - if (current) { - return models.find(m => m.model === current) || firstModelUserCanUse - } - - // Check for the last selected model - const lastSelectedModelID = ModelsService.storage?.get(ModelsService.storageKeys[type]) - // TODO(jsm): Global migration should happen once in the activation - // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) - - // if (migratedModelID && migratedModelID !== lastSelectedModelID) { - // void setModel(migratedModelID, storageKey) - // } - - // return either the last selected model or first model they can use if any - return ( - models.find(m => m.model === lastSelectedModelID) || - models.find(m => ModelsService.canUserUseModel(authStatus, m)) - ) - } - - public static getDefaultEditModel(authStatus: AuthStatus): EditModel | undefined { - return ModelsService.getDefaultModel(ModelUsage.Edit, authStatus)?.model - } - - public static getDefaultChatModel(authStatus: AuthStatus): ChatModel | undefined { - return ModelsService.getDefaultModel(ModelUsage.Chat, authStatus)?.model - } - - public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { - const modelId = typeof model === 'string' ? model : model.model - ModelsService.defaultModels.set(type, modelId) - // If we have persistent storage set, write it there - await ModelsService.storage?.set(ModelsService.storageKeys[type], modelId) - } - - public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { - const resolved = ModelsService.resolveModel(model) - if (!resolved) { - return false - } - const tier = Model.tier(resolved) - if (isEnterpriseUser(status)) { - return tier === 'enterprise' - } - if (isCodyProUser(status)) { - return tier !== 'enterprise' - } - - return tier === 'free' - } - - private static resolveModel(modelID: Model | string): Model | undefined { - if (typeof modelID !== 'string') { - return modelID - } - return ModelsService.models.find(m => m.model === modelID) - } - - /** - * Finds the model provider with the given model ID and returns its Context Window. - */ - public static getContextWindowByID(modelID: string): ModelContextWindow { - const model = ModelsService.models.find(m => m.model === modelID) - return model - ? model.contextWindow - : { input: CHAT_INPUT_TOKEN_BUDGET, output: CHAT_OUTPUT_TOKEN_BUDGET } - } - - public static getModelByID(modelID: string): Model | undefined { - return ModelsService.models.find(m => m.model === modelID) - } - - public static getModelByIDSubstringOrError(modelSubstring: string): Model { - const models = ModelsService.models.filter(m => m.model.includes(modelSubstring)) - if (models.length === 1) { - return models[0] - } - const errorMessage = - models.length > 1 - ? `Multiple models found for substring ${modelSubstring}.` - : `No models found for substring ${modelSubstring}.` - const modelsList = ModelsService.models.map(m => m.model).join(', ') - throw new Error(`${errorMessage} Available models: ${modelsList}`) - } -} - -interface Storage { - get(key: string): string | null - set(key: string, value: string): Promise -} - -export function capabilityToUsage(capability: ModelCapability): ModelUsage[] { - switch (capability) { - case 'autocomplete': - return [] - case 'chat': - return [ModelUsage.Chat, ModelUsage.Edit] - } -} From 028eac7a1e9db6f73ff9a597bf4de98ec8617c52 Mon Sep 17 00:00:00 2001 From: Beatrix Date: Fri, 5 Jul 2024 08:47:06 -0700 Subject: [PATCH 14/34] refactor: add utility functions to identify model types - Add `isCodyProModel`, `isCustomModel`, `isLocalModel`, and `isOllamaModel` utility functions to identify different types of models - Update model tags to include `Local` and provide more context around the meaning of different tags - Update usage of these utility functions in the codebase --- .../ClientSideConfigParams.kt | 8 + .../cody/protocol_generated/Constants.kt | 16 +- .../cody/protocol_generated/ContextParams.kt | 7 + .../cody/protocol_generated/Model.kt | 6 +- .../protocol_generated/ModelContextWindow.kt | 9 + .../cody/protocol_generated/ModelTag.kt | 5 + lib/shared/src/index.ts | 2 + lib/shared/src/llm-providers/clients.ts | 10 +- lib/shared/src/llm-providers/ollama/utils.ts | 2 +- lib/shared/src/models/dotcom.ts | 2 +- lib/shared/src/models/index.ts | 397 ++++++++++++++++++ lib/shared/src/models/tags.ts | 12 +- lib/shared/src/models/utils.ts | 23 + vscode/src/edit/input/get-items/model.ts | 4 +- vscode/src/models/sync.ts | 2 +- .../ModelSelectField.story.tsx | 2 +- .../modelSelectField/ModelSelectField.tsx | 8 +- 17 files changed, 493 insertions(+), 22 deletions(-) create mode 100644 agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ClientSideConfigParams.kt create mode 100644 agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextParams.kt create mode 100644 agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelContextWindow.kt create mode 100644 agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ClientSideConfigParams.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ClientSideConfigParams.kt new file mode 100644 index 00000000000..54b9eeb0c30 --- /dev/null +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ClientSideConfigParams.kt @@ -0,0 +1,8 @@ +@file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") +package com.sourcegraph.cody.protocol_generated; + +data class ClientSideConfigParams( + val apiKey: String? = null, + val apiEndpoint: String? = null, +) + diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt index 683e76a27b8..e9bc0181ea1 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt @@ -45,6 +45,20 @@ object Constants { const val remote = "remote" const val auto = "auto" const val manual = "manual" + const val accuracy = "accuracy" + const val speed = "speed" + const val balanced = "balanced" + const val recommended = "recommended" + const val deprecated = "deprecated" + const val experimental = "experimental" + const val pro = "pro" + const val free = "free" + const val enterprise = "enterprise" + const val `cody-gateway` = "cody-gateway" + const val byok = "byok" + const val ollama = "ollama" + const val dev = "dev" + const val edit = "edit" const val user = "user" const val editor = "editor" const val initial = "initial" @@ -103,7 +117,6 @@ object Constants { const val `get-chat-models` = "get-chat-models" const val openFile = "openFile" const val openLocalFileWithRange = "openLocalFileWithRange" - const val edit = "edit" const val `context_get-remote-search-repos` = "context/get-remote-search-repos" const val `context_choose-remote-search-repo` = "context/choose-remote-search-repo" const val `context_remove-remote-search-repo` = "context/remove-remote-search-repo" @@ -138,7 +151,6 @@ object Constants { const val Invoke = "Invoke" const val workspace = "workspace" const val default = "default" - const val experimental = "experimental" const val `recently used` = "recently used" const val ask = "ask" const val none = "none" diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextParams.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextParams.kt new file mode 100644 index 00000000000..c412410d0bc --- /dev/null +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ContextParams.kt @@ -0,0 +1,7 @@ +@file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") +package com.sourcegraph.cody.protocol_generated; + +data class ContextParams( + val user: Int? = null, +) + diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt index a75a2b6d5dd..e7ba0be95df 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Model.kt @@ -2,8 +2,12 @@ package com.sourcegraph.cody.protocol_generated; data class Model( - val default: Boolean, + val model: String, + val usage: List, + val contextWindow: ModelContextWindow, + val clientSideConfig: ClientSideConfigParams? = null, val provider: String, val title: String, + val tags: List, ) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelContextWindow.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelContextWindow.kt new file mode 100644 index 00000000000..b770bf66b64 --- /dev/null +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelContextWindow.kt @@ -0,0 +1,9 @@ +@file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") +package com.sourcegraph.cody.protocol_generated; + +data class ModelContextWindow( + val input: Int, + val output: Int, + val context: ContextParams? = null, +) + diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt new file mode 100644 index 00000000000..477f3227f5a --- /dev/null +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt @@ -0,0 +1,5 @@ +@file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") +package com.sourcegraph.cody.protocol_generated; + +typealias ModelTag = String // One of: accuracy, speed, balanced, recommended, deprecated, experimental, pro, free, enterprise, cody-gateway, byok, local, ollama, dev + diff --git a/lib/shared/src/index.ts b/lib/shared/src/index.ts index 04f71748b88..d9d1d69e5f7 100644 --- a/lib/shared/src/index.ts +++ b/lib/shared/src/index.ts @@ -14,6 +14,8 @@ export { ModelTag } from './models/tags' export { getProviderName, getModelInfo, + isCodyProModel, + isCustomModel, } from './models/utils' export { BotResponseMultiplexer } from './chat/bot-response-multiplexer' export { ChatClient } from './chat/chat' diff --git a/lib/shared/src/llm-providers/clients.ts b/lib/shared/src/llm-providers/clients.ts index 12b912c7667..44fe8de630c 100644 --- a/lib/shared/src/llm-providers/clients.ts +++ b/lib/shared/src/llm-providers/clients.ts @@ -1,7 +1,7 @@ import type { ChatNetworkClient, ChatNetworkClientParams } from '.' import { googleChatClient, groqChatClient, ollamaChatClient } from '..' -import { type Model, ModelsService } from '../models' -import { ModelTag } from '../models/tags' +import { ModelsService } from '../models' +import { isCustomModel } from '../models/utils' import { anthropicChatClient } from './anthropic/chat-client' export async function useCustomChatClient({ @@ -12,7 +12,7 @@ export async function useCustomChatClient({ signal, }: ChatNetworkClientParams): Promise { const model = ModelsService.getModelByID(params.model ?? '') - if (!model || isCodyGatewayModel(model)) { + if (!model || !isCustomModel(model)) { return false } @@ -33,7 +33,3 @@ export async function useCustomChatClient({ return false } - -function isCodyGatewayModel(model: Model): boolean { - return model.tags.includes(ModelTag.Gateway) -} diff --git a/lib/shared/src/llm-providers/ollama/utils.ts b/lib/shared/src/llm-providers/ollama/utils.ts index fe9b1b9ac09..c87ae079080 100644 --- a/lib/shared/src/llm-providers/ollama/utils.ts +++ b/lib/shared/src/llm-providers/ollama/utils.ts @@ -16,7 +16,7 @@ export async function fetchLocalOllamaModels(): Promise { input: OLLAMA_DEFAULT_CONTEXT_WINDOW, output: CHAT_OUTPUT_TOKEN_BUDGET, }, - tags: [ModelTag.Ollama, ModelTag.Experimental], + tags: [ModelTag.Local, ModelTag.Ollama, ModelTag.Experimental], }) ) } diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 2155fa13998..4bacd5a53a4 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -39,7 +39,7 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - tags: [ModelTag.Gateway, ModelTag.Balanced, ModelTag.Free], + tags: [ModelTag.Gateway, ModelTag.Balanced], }, { title: 'Claude 3.5 Sonnet', diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 8b137891791..31b69404ef7 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1 +1,398 @@ +import { type AuthStatus, isCodyProUser, isEnterpriseUser, isFreeUser } from '../auth/types' +import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' +import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' +import { ModelTag } from './tags' +import { type ChatModel, type EditModel, type ModelContextWindow, ModelUsage } from './types' +import { getModelInfo } from './utils' +export type ModelId = string +export type ApiVersionId = string +export type ProviderId = string + +export type ModelRef = `${ProviderId}::${ApiVersionId}::${ModelId}` + +export type ModelCapability = 'chat' | 'autocomplete' +export type ModelCategory = 'accuracy' | 'balanced' | 'speed' +export type ModelStatus = 'experimental' | 'beta' | 'stable' | 'deprecated' +export type ModelTier = 'free' | 'pro' | 'enterprise' + +export interface ContextWindow { + maxInputTokens: number + maxOutputTokens: number +} + +export interface ServerModel { + modelRef: ModelRef + displayName: string + modelName: string + capabilities: ModelCapability[] + category: ModelCategory + status: ModelStatus + tier: ModelTier + + contextWindow: ContextWindow + + clientSideConfig?: unknown +} + +/** + * Model describes an LLM model and its capabilities. + */ +export class Model { + // public default = false + /** + * The model id that includes the provider name & the model name, + * e.g. "anthropic/claude-3-sonnet-20240229" + * + * TODO(PRIME-282): Replace this with a `ModelRef` instance and introduce a separate + * "modelId" that is distinct from the "modelName". (e.g. "claude-3-sonnet" vs. "claude-3-sonnet-20240229") + */ + public readonly model: string + /** + * The usage of the model, e.g. chat or edit. + */ + public readonly usage: ModelUsage[] + /** + * The default context window of the model reserved for Chat and Context. + * {@see TokenCounter on how the token usage is calculated.} + */ + public readonly contextWindow: ModelContextWindow + + /** + * The client-specific configuration for the model. + */ + public readonly clientSideConfig?: { + /** + * The API key for the model + */ + apiKey?: string + /** + * The API endpoint for the model + */ + apiEndpoint?: string + } + + // The name of the provider of the model, e.g. "Anthropic" + public provider: string + // The title of the model, e.g. "Claude 3 Sonnet" + public readonly title: string + /** + * The tags assigned for categorizing the model. + */ + public readonly tags: ModelTag[] = [] + + constructor({ + model, + usage, + contextWindow = { + input: CHAT_INPUT_TOKEN_BUDGET, + output: CHAT_OUTPUT_TOKEN_BUDGET, + }, + clientSideConfig, + tags = [], + provider, + title, + }: ModelParams) { + this.model = model + this.usage = usage + this.contextWindow = contextWindow + this.clientSideConfig = clientSideConfig + this.tags = tags + + const info = getModelInfo(model) + this.provider = provider ?? info.provider + this.title = title ?? info.title + } + + static fromApi({ + modelRef, + displayName, + capabilities, + category, + tier, + clientSideConfig, + contextWindow, + }: ServerModel) { + // BUG: There is data loss here and the potential for ambiguity. + // BUG: We are assuming the modelRef is valid, but it might not be. + const [providerId, _, modelId] = modelRef.split('::', 3) + + const categoryTag = ((): ModelTag => { + switch (category) { + case 'accuracy': + return ModelTag.Accuracy + case 'balanced': + return ModelTag.Balanced + case 'speed': + return ModelTag.Speed + } + })() + + const tierTag = ((): ModelTag => { + switch (tier) { + case 'pro': + return ModelTag.Pro + case 'enterprise': + return ModelTag.Enterprise + default: + return ModelTag.Free + } + })() + + return new Model({ + model: modelId, + usage: capabilities.flatMap(capabilityToUsage), + contextWindow: { + input: contextWindow.maxInputTokens, + output: contextWindow.maxOutputTokens, + }, + // @ts-ignore + clientSideConfig: clientSideConfig, + tags: [categoryTag, tierTag], + provider: providerId, + title: displayName, + }) + } + + static isNewStyleEnterprise(model: Model): boolean { + return model.tags.includes(ModelTag.Enterprise) + } + + static tier(model: Model): ModelTier { + if (model.tags.includes(ModelTag.Pro)) { + return 'pro' + } + if (model.tags.includes(ModelTag.Enterprise)) { + return 'enterprise' + } + + return 'free' + } +} + +interface ModelParams { + model: string + usage: ModelUsage[] + contextWindow?: ModelContextWindow + clientSideConfig?: { + apiKey?: string + apiEndpoint?: string + } + tags?: ModelTag[] + provider?: string + title?: string +} + +/** + * ModelsService is the component responsible for keeping track of which models + * are supported on the backend, which ones are available based on the user's + * preferences, etc. + * + * TODO(PRIME-228): Update this type to be able to fetch the models from the + * Sourcegraph backend instead of being hard-coded. + * TODO(PRIME-283): Enable Cody Enterprise users to select which LLM model to + * used in the UI. (By having the relevant code paths just pull the models + * from this type.) + */ +export class ModelsService { + // Unused. Only to work around the linter complaining about a static-only class. + // When we are fetching data from the Sourcegraph backend, and relying on the + // current user's credentials, we'll need to turn this into a proper singleton + // with an initialization step on startup. + protected ModelsService() {} + + /** + * Get all the providers currently available to the user + */ + private static get models(): Model[] { + return ModelsService.primaryModels.concat(ModelsService.localModels) + } + /** + * Models available on the user's Sourcegraph instance. + */ + private static primaryModels: Model[] = [] + /** + * Models available from user's local instances, e.g. Ollama. + */ + private static localModels: Model[] = [] + + private static defaultModels: Map = new Map() + + private static storage: Storage | undefined + + private static storageKeys = { + [ModelUsage.Chat]: 'chat', + [ModelUsage.Edit]: 'editModel', + } + + public static setStorage(storage: Storage): void { + ModelsService.storage = storage + } + + public static async onConfigChange(): Promise { + try { + ModelsService.localModels = await fetchLocalOllamaModels() + } catch { + ModelsService.localModels = [] + } + } + + private static getModelsByType(usage: ModelUsage): Model[] { + return ModelsService.models.filter(model => model.usage.includes(usage)) + } + + /** + * Sets the primary models available to the user. + * NOTE: private instances can only support 1 provider ATM. + */ + public static setModels(models: Model[]): void { + ModelsService.primaryModels = models + } + + /** + * Add new models for use. + */ + public static addModels(models: Model[]): void { + const set = new Set(ModelsService.primaryModels) + for (const provider of models) { + set.add(provider) + } + ModelsService.primaryModels = Array.from(set) + } + + /** + * Gets the available models of the specified usage type, with the default model first. + * + * @param type - The usage type of the models to retrieve. + * @param authStatus - The authentication status of the user. + * @returns An array of models, with the default model first. + */ + public static getModels(type: ModelUsage, authStatus: AuthStatus): Model[] { + const models = ModelsService.getModelsByType(type) + const currentModel = ModelsService.getDefaultModel(type, authStatus) + if (!currentModel) { + return models + } + return [currentModel].concat(models.filter(m => m.model !== currentModel.model)) + } + + public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { + if (!authStatus.authenticated) { + throw new Error('You are not authenticated') + } + const current = ModelsService.defaultModels.get(type) + if (current) return current + + const models = ModelsService.getModelsByType(type) + + // Free users can only use the default model + if (isFreeUser(authStatus) || !ModelsService.storage) { + return models.find(m => ModelsService.canUserUseModel(authStatus, m)) || models[0] + } + + // Check for the last selected model + const lastSelectedModelID = ModelsService.storage.get(ModelsService.storageKeys[type]) + // TODO(jsm): Global migration should happen once in the activation + // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) + + // if (migratedModelID && migratedModelID !== lastSelectedModelID) { + // void setModel(migratedModelID, storageKey) + // } + + // return either the + // 1. last selected model + // 2. first model they can use + // 3. first model in the list + return ( + models.find(m => m.model === lastSelectedModelID) || + models.find(m => ModelsService.canUserUseModel(authStatus, m)) || + models[0] + ) + } + + public static getDefaultEditModel(authStatus: AuthStatus): EditModel | undefined { + return ModelsService.getDefaultModel(ModelUsage.Edit, authStatus)?.model + } + + public static getDefaultChatModel(authStatus: AuthStatus): ChatModel | undefined { + return ModelsService.getDefaultModel(ModelUsage.Chat, authStatus)?.model + } + + public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { + model = ModelsService.resolveModel(model) + ModelsService.defaultModels.set(type, model) + // If we have persistent storage set, write it there + await ModelsService.storage?.set(ModelsService.storageKeys[type], model.model) + } + + public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { + model = ModelsService.resolveModel(model) + const tier = Model.tier(model) + if (isEnterpriseUser(status)) { + return tier === 'enterprise' + } + if (isCodyProUser(status)) { + return tier !== 'enterprise' + } + if (isFreeUser(status)) { + return tier === 'free' + } + return false + } + + private static resolveModel(modelID: Model | string): Model { + if (typeof modelID !== 'string') { + return modelID + } + const model = ModelsService.models.find(m => m.model === modelID) + if (!model) { + throw new Error(`Unknown model: ${modelID}`) + } + return model + } + + /** + * Finds the model provider with the given model ID and returns its Context Window. + */ + public static getContextWindowByID(modelID: string): ModelContextWindow { + const model = ModelsService.models.find(m => m.model === modelID) + return model + ? model.contextWindow + : { input: CHAT_INPUT_TOKEN_BUDGET, output: CHAT_OUTPUT_TOKEN_BUDGET } + } + + public static getModelByID(modelID: string): Model | undefined { + return ModelsService.models.find(m => m.model === modelID) + } + + public static getModelByIDSubstringOrError(modelSubstring: string): Model { + const models = ModelsService.models.filter(m => m.model.includes(modelSubstring)) + if (models.length === 1) { + return models[0] + } + const errorMessage = + models.length > 1 + ? `Multiple models found for substring ${modelSubstring}.` + : `No models found for substring ${modelSubstring}.` + const modelsList = ModelsService.models.map(m => m.model).join(', ') + throw new Error(`${errorMessage} Available models: ${modelsList}`) + } + + public static hasModelTag(model: Model, modelTag: ModelTag): boolean { + return model.tags.includes(modelTag) + } +} + +interface Storage { + get(key: string): string | null + set(key: string, value: string): Promise +} + +export function capabilityToUsage(capability: ModelCapability): ModelUsage[] { + switch (capability) { + case 'autocomplete': + return [] + case 'chat': + return [ModelUsage.Chat, ModelUsage.Edit] + } +} diff --git a/lib/shared/src/models/tags.ts b/lib/shared/src/models/tags.ts index dc3de80357e..a66e210a5d2 100644 --- a/lib/shared/src/models/tags.ts +++ b/lib/shared/src/models/tags.ts @@ -1,20 +1,28 @@ +/** + * Enum representing various tags that can be applied to a model. + * These tags are used to categorize and filter models based on model's characteristics. + * This helps clients to identify the origins and capabilities of a model. + */ export enum ModelTag { // UI Groups Accuracy = 'accuracy', Speed = 'speed', Balanced = 'balanced', + + // Statuses Recommended = 'recommended', Deprecated = 'deprecated', Experimental = 'experimental', - // Tiers + // Tiers - the level of access to the model Pro = 'pro', Free = 'free', Enterprise = 'enterprise', - // Host / Model Type + // Origins - where the model comes from Gateway = 'cody-gateway', BYOK = 'byok', + Local = 'local', Ollama = 'ollama', Dev = 'dev', } diff --git a/lib/shared/src/models/utils.ts b/lib/shared/src/models/utils.ts index 5fc3c437e7d..97f19409abc 100644 --- a/lib/shared/src/models/utils.ts +++ b/lib/shared/src/models/utils.ts @@ -1,3 +1,6 @@ +import { type Model, ModelsService } from '.' +import { ModelTag } from '..' + export function getProviderName(name: string): string { const providerName = name.toLowerCase() switch (providerName) { @@ -26,3 +29,23 @@ export function getModelInfo(modelID: string): { const title = (rest.at(-1) || '').replace(/-/g, ' ') return { provider, title } } + +export function isCodyProModel(model: Model): boolean { + return ModelsService.hasModelTag(model, ModelTag.Pro) +} + +export function isLocalModel(model: Model): boolean { + return ModelsService.hasModelTag(model, ModelTag.Local) +} + +export function isCustomModel(model: Model): boolean { + return ( + ModelsService.hasModelTag(model, ModelTag.Local) || + ModelsService.hasModelTag(model, ModelTag.Dev) || + ModelsService.hasModelTag(model, ModelTag.BYOK) + ) +} + +export function isOllamaModel(model: Model): boolean { + return model.provider.toLowerCase() === 'ollama' || ModelsService.hasModelTag(model, ModelTag.Ollama) +} diff --git a/vscode/src/edit/input/get-items/model.ts b/vscode/src/edit/input/get-items/model.ts index 8d4a6df22ce..0ef092310d6 100644 --- a/vscode/src/edit/input/get-items/model.ts +++ b/vscode/src/edit/input/get-items/model.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' -import { type EditModel, Model, isDefined } from '@sourcegraph/cody-shared' +import { type EditModel, type Model, isCodyProModel, isDefined } from '@sourcegraph/cody-shared' import { QUICK_PICK_ITEM_CHECKED_PREFIX, QUICK_PICK_ITEM_EMPTY_INDENT_PREFIX, @@ -35,7 +35,7 @@ export const getModelOptionItems = (modelOptions: Model[], isCodyPro: boolean): alwaysShow: true, model: modelOption.model, modelTitle: modelOption.title, - codyProOnly: Model.isCodyPro(modelOption), + codyProOnly: isCodyProModel(modelOption), } }) .filter(isDefined) diff --git a/vscode/src/models/sync.ts b/vscode/src/models/sync.ts index ffeadf716ca..54ad2a7c993 100644 --- a/vscode/src/models/sync.ts +++ b/vscode/src/models/sync.ts @@ -120,7 +120,7 @@ export function registerModelsFromVSCodeConfiguration() { output: m.outputTokens ?? ANSWER_TOKENS, }, clientSideConfig: { apiKey: m.apiKey, apiEndpoint: m.apiEndpoint }, - tags: [ModelTag.Dev, ModelTag.Experimental], + tags: [ModelTag.Local, ModelTag.BYOK, ModelTag.Experimental], }) ) ) diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx index 2b775b92bab..5f39d56049c 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.story.tsx @@ -15,7 +15,7 @@ const MODELS: Model[] = [ model: 'ollama/llama-3', contextWindow: { input: 100, output: 100 }, usage: [ModelUsage.Chat], - tags: [ModelTag.Ollama, ModelTag.Dev], + tags: [ModelTag.Ollama, ModelTag.Local], }, ] diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx index 92d24d2cdc1..c7d90c898a9 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx @@ -1,4 +1,4 @@ -import { Model, ModelTag } from '@sourcegraph/cody-shared' +import { type Model, ModelTag, isCodyProModel } from '@sourcegraph/cody-shared' import { clsx } from 'clsx' import { BookOpenIcon, BuildingIcon, ExternalLinkIcon } from 'lucide-react' import { type FunctionComponent, type ReactNode, useCallback, useMemo } from 'react' @@ -53,7 +53,7 @@ export const ModelSelectField: React.FunctionComponent<{ (model: Model): void => { telemetryRecorder.recordEvent('cody.modelSelector', 'select', { metadata: { - modelIsCodyProOnly: Model.isCodyPro(model) ? 1 : 0, + modelIsCodyProOnly: isCodyProModel(model) ? 1 : 0, isCodyProUser: isCodyProUser ? 1 : 0, }, privateMetadata: { @@ -63,7 +63,7 @@ export const ModelSelectField: React.FunctionComponent<{ }, }) - if (showCodyProBadge && Model.isCodyPro(model)) { + if (showCodyProBadge && isCodyProModel(model)) { getVSCodeAPI().postMessage({ command: 'links', value: 'https://sourcegraph.com/cody/subscription', @@ -271,7 +271,7 @@ function modelAvailability( if (!userInfo.isDotComUser && userInfo.isOldStyleEnterpriseUser) { return 'not-selectable-on-enterprise' } - if (Model.isCodyPro(model) && !userInfo.isCodyProUser) { + if (isCodyProModel(model) && !userInfo.isCodyProUser) { return 'needs-cody-pro' } return 'available' From ff5cbbe0c693e985d2e135f95aaf284e9fbd64ce Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Sat, 6 Jul 2024 20:48:18 -0700 Subject: [PATCH 15/34] Reverted missing file --- lib/shared/src/models/index.ts | 390 +++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 8b137891791..6c0fb3bc75f 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1 +1,391 @@ +import { type AuthStatus, isCodyProUser, isEnterpriseUser, isFreeUser } from '../auth/types' +import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' +import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' +import { ModelTag } from './tags' +import { type ChatModel, type EditModel, type ModelContextWindow, ModelUsage } from './types' +import { getModelInfo } from './utils' +export type ModelId = string +export type ApiVersionId = string +export type ProviderId = string + +export type ModelRef = `${ProviderId}::${ApiVersionId}::${ModelId}` + +export type ModelCapability = 'chat' | 'autocomplete' +export type ModelCategory = 'accuracy' | 'balanced' | 'speed' +export type ModelStatus = 'experimental' | 'beta' | 'stable' | 'deprecated' +export type ModelTier = 'free' | 'pro' | 'enterprise' + +export interface ContextWindow { + maxInputTokens: number + maxOutputTokens: number +} + +export interface ServerModel { + modelRef: ModelRef + displayName: string + modelName: string + capabilities: ModelCapability[] + category: ModelCategory + status: ModelStatus + tier: ModelTier + + contextWindow: ContextWindow + + clientSideConfig?: unknown +} + +/** + * Model describes an LLM model and its capabilities. + */ +export class Model { + /** + * The model id that includes the provider name & the model name, + * e.g. "anthropic/claude-3-sonnet-20240229" + * + * TODO(PRIME-282): Replace this with a `ModelRef` instance and introduce a separate + * "modelId" that is distinct from the "modelName". (e.g. "claude-3-sonnet" vs. "claude-3-sonnet-20240229") + */ + public readonly model: string + /** + * The usage of the model, e.g. chat or edit. + */ + public readonly usage: ModelUsage[] + /** + * The default context window of the model reserved for Chat and Context. + * {@see TokenCounter on how the token usage is calculated.} + */ + public readonly contextWindow: ModelContextWindow + + /** + * The client-specific configuration for the model. + */ + public readonly clientSideConfig?: { + /** + * The API key for the model + */ + apiKey?: string + /** + * The API endpoint for the model + */ + apiEndpoint?: string + } + + // The name of the provider of the model, e.g. "Anthropic" + public provider: string + // The title of the model, e.g. "Claude 3 Sonnet" + public readonly title: string + /** + * The tags assigned for categorizing the model. + */ + public readonly tags: ModelTag[] = [] + + constructor({ + model, + usage, + contextWindow = { + input: CHAT_INPUT_TOKEN_BUDGET, + output: CHAT_OUTPUT_TOKEN_BUDGET, + }, + clientSideConfig, + tags = [], + provider, + title, + }: ModelParams) { + this.model = model + this.usage = usage + this.contextWindow = contextWindow + this.clientSideConfig = clientSideConfig + this.tags = tags + + const info = getModelInfo(model) + this.provider = provider ?? info.provider + this.title = title ?? info.title + } + + static fromApi({ + modelRef, + displayName, + capabilities, + category, + tier, + clientSideConfig, + contextWindow, + }: ServerModel) { + // BUG: There is data loss here and the potential for ambiguity. + // BUG: We are assuming the modelRef is valid, but it might not be. + const [providerId, _, modelId] = modelRef.split('::', 3) + + const categoryTag = ((): ModelTag => { + switch (category) { + case 'accuracy': + return ModelTag.Accuracy + case 'balanced': + return ModelTag.Balanced + case 'speed': + return ModelTag.Speed + } + })() + + const tierTag = ((): ModelTag => { + switch (tier) { + case 'free': + return ModelTag.Free + case 'pro': + return ModelTag.Pro + case 'enterprise': + return ModelTag.Enterprise + } + })() + + return new Model({ + model: modelId, + usage: capabilities.flatMap(capabilityToUsage), + contextWindow: { + input: contextWindow.maxInputTokens, + output: contextWindow.maxOutputTokens, + }, + // @ts-ignore + clientSideConfig: clientSideConfig, + tags: [categoryTag, tierTag], + provider: providerId, + title: displayName, + }) + } + + static isNewStyleEnterprise(model: Model): boolean { + return model.tags.includes(ModelTag.Enterprise) + } + + static tier(model: Model): ModelTier { + if (model.tags.includes(ModelTag.Free)) { + return 'free' + } + if (model.tags.includes(ModelTag.Pro)) { + return 'pro' + } + if (model.tags.includes(ModelTag.Enterprise)) { + return 'enterprise' + } + + return 'pro' + } + + static isCodyPro(model?: Model): boolean { + return Boolean(model?.tags.includes(ModelTag.Pro)) + } +} + +interface ModelParams { + model: string + usage: ModelUsage[] + contextWindow?: ModelContextWindow + clientSideConfig?: { + apiKey?: string + apiEndpoint?: string + } + tags?: ModelTag[] + provider?: string + title?: string +} + +/** + * ModelsService is the component responsible for keeping track of which models + * are supported on the backend, which ones are available based on the user's + * preferences, etc. + * + * TODO(PRIME-228): Update this type to be able to fetch the models from the + * Sourcegraph backend instead of being hard-coded. + * TODO(PRIME-283): Enable Cody Enterprise users to select which LLM model to + * used in the UI. (By having the relevant code paths just pull the models + * from this type.) + */ +export class ModelsService { + // Unused. Only to work around the linter complaining about a static-only class. + // When we are fetching data from the Sourcegraph backend, and relying on the + // current user's credentials, we'll need to turn this into a proper singleton + // with an initialization step on startup. + protected ModelsService() {} + + /** + * Get all the providers currently available to the user + */ + private static get models(): Model[] { + return ModelsService.primaryModels.concat(ModelsService.localModels) + } + /** + * Models available on the user's Sourcegraph instance. + */ + private static primaryModels: Model[] = [] + /** + * Models available from user's local instances, e.g. Ollama. + */ + private static localModels: Model[] = [] + + private static defaultModels: Map = new Map() + + private static storage: Storage | undefined + + private static storageKeys = { + [ModelUsage.Chat]: 'chat', + [ModelUsage.Edit]: 'editModel', + } + + public static setStorage(storage: Storage): void { + ModelsService.storage = storage + } + + public static async onConfigChange(): Promise { + try { + ModelsService.localModels = await fetchLocalOllamaModels() + } catch { + ModelsService.localModels = [] + } + } + + private static getModelsByType(usage: ModelUsage): Model[] { + return ModelsService.models.filter(model => model.usage.includes(usage)) + } + + /** + * Sets the primary models available to the user. + * NOTE: private instances can only support 1 provider ATM. + */ + public static setModels(models: Model[]): void { + console.trace('MODELS ARE: ', models) + ModelsService.primaryModels = models + } + + /** + * Add new models for use. + */ + public static addModels(models: Model[]): void { + const set = new Set(ModelsService.primaryModels) + for (const provider of models) { + set.add(provider) + } + ModelsService.primaryModels = Array.from(set) + } + + /** + * Gets the available models of the specified usage type, with the default model first. + * + * @param type - The usage type of the models to retrieve. + * @param authStatus - The authentication status of the user. + * @returns An array of models, with the default model first. + */ + public static getModels(type: ModelUsage, authStatus: AuthStatus): Model[] { + const models = ModelsService.getModelsByType(type) + const currentModel = ModelsService.getDefaultModel(type, authStatus) + if (!currentModel) { + return models + } + return [currentModel].concat(models.filter(m => m.model !== currentModel.model)) + } + + public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { + const models = ModelsService.getModelsByType(type) + const firstModelUserCanUse = models.find(m => ModelsService.canUserUseModel(authStatus, m)) + if (!authStatus.authenticated || isFreeUser(authStatus)) { + return firstModelUserCanUse + } + const current = ModelsService.defaultModels.get(type) + if (current) { + return models.find(m => m.model === current) || firstModelUserCanUse + } + + // Check for the last selected model + const lastSelectedModelID = ModelsService.storage?.get(ModelsService.storageKeys[type]) + // TODO(jsm): Global migration should happen once in the activation + // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) + + // if (migratedModelID && migratedModelID !== lastSelectedModelID) { + // void setModel(migratedModelID, storageKey) + // } + + // return either the last selected model or first model they can use if any + return ( + models.find(m => m.model === lastSelectedModelID) || + models.find(m => ModelsService.canUserUseModel(authStatus, m)) + ) + } + + public static getDefaultEditModel(authStatus: AuthStatus): EditModel | undefined { + return ModelsService.getDefaultModel(ModelUsage.Edit, authStatus)?.model + } + + public static getDefaultChatModel(authStatus: AuthStatus): ChatModel | undefined { + return ModelsService.getDefaultModel(ModelUsage.Chat, authStatus)?.model + } + + public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { + const modelId = typeof model === 'string' ? model : model.model + ModelsService.defaultModels.set(type, modelId) + // If we have persistent storage set, write it there + await ModelsService.storage?.set(ModelsService.storageKeys[type], modelId) + } + + public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { + const resolved = ModelsService.resolveModel(model) + if (!resolved) { + return false + } + const tier = Model.tier(resolved) + if (isEnterpriseUser(status)) { + return tier === 'enterprise' + } + if (isCodyProUser(status)) { + return tier !== 'enterprise' + } + + return tier === 'free' + } + + private static resolveModel(modelID: Model | string): Model | undefined { + if (typeof modelID !== 'string') { + return modelID + } + return ModelsService.models.find(m => m.model === modelID) + } + + /** + * Finds the model provider with the given model ID and returns its Context Window. + */ + public static getContextWindowByID(modelID: string): ModelContextWindow { + const model = ModelsService.models.find(m => m.model === modelID) + return model + ? model.contextWindow + : { input: CHAT_INPUT_TOKEN_BUDGET, output: CHAT_OUTPUT_TOKEN_BUDGET } + } + + public static getModelByID(modelID: string): Model | undefined { + return ModelsService.models.find(m => m.model === modelID) + } + + public static getModelByIDSubstringOrError(modelSubstring: string): Model { + const models = ModelsService.models.filter(m => m.model.includes(modelSubstring)) + if (models.length === 1) { + return models[0] + } + const errorMessage = + models.length > 1 + ? `Multiple models found for substring ${modelSubstring}.` + : `No models found for substring ${modelSubstring}.` + const modelsList = ModelsService.models.map(m => m.model).join(', ') + throw new Error(`${errorMessage} Available models: ${modelsList}`) + } +} + +interface Storage { + get(key: string): string | null + set(key: string, value: string): Promise +} + +export function capabilityToUsage(capability: ModelCapability): ModelUsage[] { + switch (capability) { + case 'autocomplete': + return [] + case 'chat': + return [ModelUsage.Chat, ModelUsage.Edit] + } +} From 81099b3ea6239e8b2a491fe170c1dba338e4bc8a Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Mon, 8 Jul 2024 10:32:01 -0700 Subject: [PATCH 16/34] updated recordings --- .../cody-chat_103640681/recording.har.yaml | 94 ++ .../recording.har.yaml | 1090 ++++++++--------- 2 files changed, 638 insertions(+), 546 deletions(-) diff --git a/agent/recordings/cody-chat_103640681/recording.har.yaml b/agent/recordings/cody-chat_103640681/recording.har.yaml index 1a27946d32e..688fa18b39d 100644 --- a/agent/recordings/cody-chat_103640681/recording.har.yaml +++ b/agent/recordings/cody-chat_103640681/recording.har.yaml @@ -2180,6 +2180,100 @@ log: send: 0 ssl: -1 wait: 0 + - _id: d4b7d3b31a40b2ba1d1ac65206c49eff + _order: 0 + cache: {} + request: + bodySize: 193 + cookies: [] + headers: + - _fromType: array + name: authorization + value: token + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d + - _fromType: array + name: content-type + value: application/json; charset=utf-8 + - _fromType: array + name: user-agent + value: cody-cli / 0.1.0-SNAPSHOT + - _fromType: array + name: accept + value: "*/*" + - _fromType: array + name: content-length + value: "193" + - _fromType: array + name: accept-encoding + value: gzip,deflate + - name: host + value: sourcegraph.com + headersSize: 332 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json; charset=utf-8 + params: [] + textJSON: + query: |2 + + query EvaluateFeatureFlag($flagName: String!) { + evaluateFeatureFlag(flagName: $flagName) + } + variables: + flagName: cody-autocomplete-latency-experiment-flag + queryString: + - name: EvaluateFeatureFlag + value: null + url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag + response: + bodySize: 37 + content: + mimeType: application/json + size: 37 + text: "{\"data\":{\"evaluateFeatureFlag\":true}}" + cookies: [] + headers: + - name: date + value: Mon, 08 Jul 2024 17:30:18 GMT + - name: content-type + value: application/json + - name: content-length + value: "37" + - name: connection + value: keep-alive + - name: access-control-allow-credentials + value: "true" + - name: access-control-allow-origin + value: "" + - name: cache-control + value: no-cache, max-age=0 + - 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: 1301 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-07-08T17:30:18.101Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 - _id: 733f60b08a7598b02125f522e171b133 _order: 0 cache: {} diff --git a/agent/recordings/defaultClient_631904893/recording.har.yaml b/agent/recordings/defaultClient_631904893/recording.har.yaml index 108563c6a5a..9f303a46fe5 100644 --- a/agent/recordings/defaultClient_631904893/recording.har.yaml +++ b/agent/recordings/defaultClient_631904893/recording.har.yaml @@ -906,6 +906,406 @@ log: send: 0 ssl: -1 wait: 0 + - _id: 995796292d70192b0f8ad4f75d87443e + _order: 0 + cache: {} + request: + bodySize: 2417 + cookies: [] + headers: + - name: content-type + value: application/json + - name: accept-encoding + value: gzip;q=0 + - name: authorization + value: token + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d + - name: user-agent + value: defaultClient / v1 + - name: traceparent + value: 00-43bbf5f684a65911bbefc6f9aa63db2a-a93b77911242cd8c-01 + - name: connection + value: keep-alive + - name: host + value: sourcegraph.com + headersSize: 415 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json + params: [] + textJSON: + maxTokensToSample: 4000 + messages: + - speaker: system + text: You are Cody, an AI coding assistant from Sourcegraph. + - speaker: human + text: >- + Codebase context from file src/squirrel.ts: + + ```typescript + + /** + * Squirrel is an interface that mocks something completely unrelated to squirrels. + * It is related to the implementation of precise code navigation in Sourcegraph. + */ + export interface Squirrel {} + + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/multiple-selections.ts: + ```typescript + function outer() { + /* SELECTION_START */ + return function inner() {} + /* SELECTION_END */ + } + + /* SELECTION_2_START */ + function anotherFunction() {} + /* SELECTION_2_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/Heading.tsx: + ```typescript + import React = require("react"); + + interface HeadingProps { + text: string; + level?: number; + } + + /* CURSOR */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); + + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

                  Messages

                  +
                    + {messages.map((message) => ( +
                  • {message.text}
                  • ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + My selected code from codebase file src/animal.ts:1-6: + ``` + + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: >- + You have access to the provided codebase context. + + + Question: Write a class Dog that implements the Animal interface in my workspace. Show the code only, no explanation needed. + model: anthropic/claude-3-sonnet-20240229 + temperature: 0 + topK: -1 + topP: -1 + queryString: + - name: api-version + value: "1" + - name: client-name + value: defaultclient + - name: client-version + value: v1 + url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + response: + bodySize: 4058 + content: + mimeType: text/event-stream + size: 4058 + text: >+ + event: completion + + data: {"completion":"```typescript\nclass Dog implements Animal {\n name: string;\n isMammal: boolean = true;\n\n constructor(name: string) {\n this.name = name;\n }\n\n makeAnimalSound(): string {\n return \"Woof!\";\n }\n}\n```","stopReason":"end_turn"} + + + event: done + + data: {} + + cookies: [] + headers: + - name: date + value: Mon, 08 Jul 2024 17:30:21 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: 1299 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-07-08T17:30:19.203Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 + - _id: 4669fca2fa47ddd0468c59cf7472b21b + _order: 0 + cache: {} + request: + bodySize: 2085 + cookies: [] + headers: + - name: content-type + value: application/json + - name: accept-encoding + value: gzip;q=0 + - name: authorization + value: token + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d + - name: user-agent + value: defaultClient / v1 + - name: traceparent + value: 00-14b721a271f989ce55933e61bc438130-bba7021bad575eff-01 + - name: connection + value: keep-alive + - name: host + value: sourcegraph.com + headersSize: 415 + httpVersion: HTTP/1.1 + method: POST + postData: + mimeType: application/json + params: [] + textJSON: + maxTokensToSample: 4000 + messages: + - speaker: system + text: You are Cody, an AI coding assistant from Sourcegraph. + - speaker: human + text: >- + Codebase context from file src/squirrel.ts: + + ```typescript + + /** + * Squirrel is an interface that mocks something completely unrelated to squirrels. + * It is related to the implementation of precise code navigation in Sourcegraph. + */ + export interface Squirrel {} + + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/multiple-selections.ts: + ```typescript + function outer() { + /* SELECTION_START */ + return function inner() {} + /* SELECTION_END */ + } + + /* SELECTION_2_START */ + function anotherFunction() {} + /* SELECTION_2_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/Heading.tsx: + ```typescript + import React = require("react"); + + interface HeadingProps { + text: string; + level?: number; + } + + /* CURSOR */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); + + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

                    Messages

                    +
                      + {messages.map((message) => ( +
                    • {message.text}
                    • ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ + export interface Animal { + name: string + makeAnimalSound(): string + isMammal: boolean + } + /* SELECTION_END */ + ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + You have access to the provided codebase context. + + Question: What is Squirrel? + model: anthropic/claude-3-sonnet-20240229 + temperature: 0 + topK: -1 + topP: -1 + queryString: + - name: api-version + value: "1" + - name: client-name + value: defaultclient + - name: client-version + value: v1 + url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 + response: + bodySize: 4494 + content: + mimeType: text/event-stream + size: 4494 + text: >+ + event: completion + + data: {"completion":"Based on the codebase context from `src/squirrel.ts`, `Squirrel` is an interface that is described as mocking \"something completely unrelated to squirrels.\" The comment further explains that it is related to the implementation of precise code navigation in Sourcegraph.","stopReason":"end_turn"} + + + event: done + + data: {} + + cookies: [] + headers: + - name: date + value: Mon, 08 Jul 2024 17:30:23 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: 1299 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-07-08T17:30:21.984Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 - _id: 4a073cecbb07c3cb5e753bf49615d886 _order: 0 cache: {} @@ -1754,279 +2154,44 @@ log: * kurusch - * kurwa - - * kusama - - * kuznetsov - - * kvass - - * kvell - - * kveldulf - - * kvetch - - * kvetchnikoff - - * kvetching - - * kvik - - * kwanza - - * kwa - - * kyaraben - - * kyathos - - * kyoto - - * kyrgyz - - * kyrgyzstan - - - I hope this list is helpful! If you have any other questions, just let me know. - - speaker: human - text: georgey - model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 - response: - bodySize: 1003 - content: - mimeType: text/event-stream - size: 1003 - text: >+ - event: completion - - data: {"completion":"Sure thing! Here is your requested word:\n\n* festivus\n\nI hope this is what you were looking for. If you have any other questions or need assistance with something else, just let me know!","stopReason":"stop"} - - - event: done - - data: {} - - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 23:22:47 GMT - - name: content-type - value: text/event-stream - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "95" - - 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: 1405 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T23:22:46.375Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: ff4649261f59bb8e70c7cfebdefb2481 - _order: 0 - cache: {} - request: - bodySize: 414 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-a6e1787cf77726ad0eb50abef3ee6414-020ec6dab789437b-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 401 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - 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: I have a turtle named "potter", reply single "ok" if you understand. - model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 - response: - bodySize: 12420 - content: - mimeType: text/event-stream - size: 12420 - text: >+ - event: completion + * kurwa - data: {"completion":"Sure, I understand that you have a turtle named \"potter\". Just to confirm, is there anything specific you would like me to help you with related to your turtle or coding that you would like to get started on? Otherwise, I'm here to assist you with any questions or problems you might have about coding. If you have any questions or need help with something, feel free to ask!\n\nFor example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} + * kusama + * kuznetsov - event: done + * kvass - data: {} + * kvell - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 23:22:48 GMT - - name: content-type - value: text/event-stream - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "94" - - 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: 1405 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T23:22:47.624Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 2fc596fd48d754548136ecb8930c70e1 - _order: 0 - cache: {} - request: - bodySize: 1689 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-99600c85c3300524e513e57e8fd05d53-28ea26be1ac44a65-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 401 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - 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: I have a turtle named "potter", reply single "ok" if you understand. - - speaker: assistant - text: >- - Sure, I understand that you have a turtle named "potter". Just - to confirm, is there anything specific you would like me to - help you with related to your turtle or coding that you would - like to get started on? Otherwise, I'm here to assist you with - any questions or problems you might have about coding. If you - have any questions or need help with something, feel free to - ask! + * kveldulf + * kvetch - For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. + * kvetchnikoff + * kvetching - If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. + * kvik + * kwanza - In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! + * kwa + * kyaraben - I hope this helps. Do you have any questions for me? + * kyathos + + * kyoto + + * kyrgyz + + * kyrgyzstan + + + I hope this list is helpful! If you have any other questions, just let me know. - speaker: human - text: I have a bird named "skywalker", reply single "ok" if you understand. + text: georgey model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2038,14 +2203,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 14761 + bodySize: 1003 content: mimeType: text/event-stream - size: 14761 + size: 1003 text: >+ event: completion - data: {"completion":"I understand that you have a bird named \"skywalker\". It's always fun to have pets and give them unique names! Do you have any questions or need help with something related to coding or your pet bird? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} + data: {"completion":"Sure thing! Here is your requested word:\n\n* festivus\n\nI hope this is what you were looking for. If you have any other questions or need assistance with something else, just let me know!","stopReason":"stop"} event: done @@ -2055,7 +2220,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:49 GMT + value: Thu, 27 Jun 2024 23:22:47 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2063,7 +2228,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "92" + value: "95" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2086,7 +2251,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:48.988Z + startedDateTime: 2024-06-27T23:22:46.375Z time: 0 timings: blocked: -1 @@ -2096,11 +2261,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 98f2884871b118d4b9b09e5be5779896 + - _id: ff4649261f59bb8e70c7cfebdefb2481 _order: 0 cache: {} request: - bodySize: 3143 + bodySize: 414 cookies: [] headers: - name: content-type @@ -2113,7 +2278,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-a732fc4df74e86a9dec21f1d38a91822-6deb1c4425608122-01 + value: 00-a6e1787cf77726ad0eb50abef3ee6414-020ec6dab789437b-01 - name: connection value: keep-alive - name: host @@ -2133,51 +2298,6 @@ log: text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human text: I have a turtle named "potter", reply single "ok" if you understand. - - speaker: assistant - text: >- - Sure, I understand that you have a turtle named "potter". Just - to confirm, is there anything specific you would like me to - help you with related to your turtle or coding that you would - like to get started on? Otherwise, I'm here to assist you with - any questions or problems you might have about coding. If you - have any questions or need help with something, feel free to - ask! - - - For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - - - If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. - - - In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! - - - I hope this helps. Do you have any questions for me? - - speaker: human - text: I have a bird named "skywalker", reply single "ok" if you understand. - - speaker: assistant - text: >- - I understand that you have a bird named "skywalker". It's - always fun to have pets and give them unique names! Do you - have any questions or need help with something related to - coding or your pet bird? I'm here to help with any questions - or problems you might have. Just let me know what you'd like - to talk about. - - - If you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - - - If you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about. - - - In the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey! - - - I hope this helps. Do you have any questions for me? - - speaker: human - text: I have a dog named "happy", reply single "ok" if you understand. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2189,14 +2309,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 10973 + bodySize: 12420 content: mimeType: text/event-stream - size: 10973 + size: 12420 text: >+ event: completion - data: {"completion":"I understand that you have a dog named \"happy\". Dogs are great companions and it's always fun to give them unique names. Do you have any questions or need help with something related to coding or your dog? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or dogs, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about dogs: Did you know that dogs are able to understand and respond to a wide range of words and commands? Some dogs are even able to learn hundreds of words and commands!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} + data: {"completion":"Sure, I understand that you have a turtle named \"potter\". Just to confirm, is there anything specific you would like me to help you with related to your turtle or coding that you would like to get started on? Otherwise, I'm here to assist you with any questions or problems you might have about coding. If you have any questions or need help with something, feel free to ask!\n\nFor example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} event: done @@ -2206,7 +2326,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:51 GMT + value: Thu, 27 Jun 2024 23:22:48 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2214,7 +2334,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "91" + value: "94" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2237,7 +2357,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:50.412Z + startedDateTime: 2024-06-27T23:22:47.624Z time: 0 timings: blocked: -1 @@ -2247,11 +2367,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: e314fb6c9f93ccee2363909a66529b07 + - _id: 2fc596fd48d754548136ecb8930c70e1 _order: 0 cache: {} request: - bodySize: 1685 + bodySize: 1689 cookies: [] headers: - name: content-type @@ -2264,7 +2384,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-350e6487be7c211d20936b5717396f13-0d4d2e919924abb4-01 + value: 00-99600c85c3300524e513e57e8fd05d53-28ea26be1ac44a65-01 - name: connection value: keep-alive - name: host @@ -2306,7 +2426,7 @@ log: I hope this helps. Do you have any questions for me? - speaker: human - text: I have a tiger named "zorro", reply single "ok" if you understand + text: I have a bird named "skywalker", reply single "ok" if you understand. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2318,14 +2438,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 22370 + bodySize: 14761 content: mimeType: text/event-stream - size: 22370 + size: 14761 text: >+ event: completion - data: {"completion":"I understand that you have a tiger named \"zorro\". Is there anything specific you would like to ask or discuss about your tiger or related to coding that you would like me to help with?\n\nAs a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges.\n\nIf you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything.\n\nIf you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\nI hope this helps. Do you have any questions or concerns for me?\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} + data: {"completion":"I understand that you have a bird named \"skywalker\". It's always fun to have pets and give them unique names! Do you have any questions or need help with something related to coding or your pet bird? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} event: done @@ -2335,7 +2455,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:52 GMT + value: Thu, 27 Jun 2024 23:22:49 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2343,7 +2463,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "90" + value: "92" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2366,7 +2486,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:51.605Z + startedDateTime: 2024-06-27T23:22:48.988Z time: 0 timings: blocked: -1 @@ -2376,11 +2496,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 7c1d096239c8d170c18db5501e43e433 + - _id: 98f2884871b118d4b9b09e5be5779896 _order: 0 cache: {} request: - bodySize: 3463 + bodySize: 3143 cookies: [] headers: - name: content-type @@ -2393,7 +2513,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-aa645675e25db20a958f4bbb5b4d9659-e7951db609ddd9a9-01 + value: 00-a732fc4df74e86a9dec21f1d38a91822-6deb1c4425608122-01 - name: connection value: keep-alive - name: host @@ -2435,30 +2555,29 @@ log: I hope this helps. Do you have any questions for me? - speaker: human - text: I have a tiger named "zorro", reply single "ok" if you understand + text: I have a bird named "skywalker", reply single "ok" if you understand. - speaker: assistant text: >- - I understand that you have a tiger named "zorro". Is there - anything specific you would like to ask or discuss about your - tiger or related to coding that you would like me to help - with? - - - As a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges. + I understand that you have a bird named "skywalker". It's + always fun to have pets and give them unique names! Do you + have any questions or need help with something related to + coding or your pet bird? I'm here to help with any questions + or problems you might have. Just let me know what you'd like + to talk about. - If you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything. + If you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - If you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about. + If you just want to chat about coding or birds, I'm happy to do that too! Just let me know what you'd like to talk about. - I hope this helps. Do you have any questions or concerns for me? + In the meantime, here's a fun fact about birds: Did you know that some species of birds are able to fly at very high speeds? The peregrine falcon, for example, is the fastest bird in the world, and can reach speeds of over 240 miles per hour when diving to catch its prey! - (By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!) + I hope this helps. Do you have any questions for me? - speaker: human - text: What pets do I have? + text: I have a dog named "happy", reply single "ok" if you understand. model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2470,14 +2589,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 12007 + bodySize: 10973 content: mimeType: text/event-stream - size: 12007 + size: 10973 text: >+ event: completion - data: {"completion":"Based on the information you have provided, it appears that you have a turtle named \"potter\" and a tiger named \"zorro\". I am a machine learning model, and my ability to accurately and comprehensively understand and recall information about a user is limited. I am intended to be used as a coding assistant, and I am not able to access or retrieve personal information about users unless it has been explicitly shared with me in the course of our conversation.\n\nI hope this helps clarify my capabilities and limitations. Do you have any questions or concerns about using me as a coding assistant, or would you like me to help you with any coding-related questions or problems you might have? I'm here to help with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} + data: {"completion":"I understand that you have a dog named \"happy\". Dogs are great companions and it's always fun to give them unique names. Do you have any questions or need help with something related to coding or your dog? I'm here to help with any questions or problems you might have. Just let me know what you'd like to talk about.\n\nIf you have any questions or need help with something specific, feel free to ask. For example, if you're working on a programming project and you're encountering an error or you're not sure how to accomplish a particular task, you can share the relevant code and the error message or description of the problem with me, and I can help you understand what's causing the problem and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack.\n\nIf you just want to chat about coding or dogs, I'm happy to do that too! Just let me know what you'd like to talk about.\n\nIn the meantime, here's a fun fact about dogs: Did you know that dogs are able to understand and respond to a wide range of words and commands? Some dogs are even able to learn hundreds of words and commands!\n\nI hope this helps. Do you have any questions for me?","stopReason":"stop"} event: done @@ -2487,7 +2606,7 @@ log: cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 23:22:54 GMT + value: Thu, 27 Jun 2024 23:22:51 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2495,7 +2614,7 @@ log: - name: connection value: keep-alive - name: retry-after - value: "88" + value: "91" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2518,7 +2637,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T23:22:53.211Z + startedDateTime: 2024-06-27T23:22:50.412Z time: 0 timings: blocked: -1 @@ -2528,11 +2647,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: fff09869fd6dda857262c86442b376a0 + - _id: e314fb6c9f93ccee2363909a66529b07 _order: 0 cache: {} request: - bodySize: 2500 + bodySize: 1685 cookies: [] headers: - name: content-type @@ -2545,7 +2664,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-5f9cb2ca3c860d7600be54c7e4bfa3b1-d035ed7532ad7938-01 + value: 00-350e6487be7c211d20936b5717396f13-0d4d2e919924abb4-01 - name: connection value: keep-alive - name: host @@ -2564,112 +2683,31 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human + text: I have a turtle named "potter", reply single "ok" if you understand. + - speaker: assistant text: >- - Codebase context from file src/squirrel.ts: + Sure, I understand that you have a turtle named "potter". Just + to confirm, is there anything specific you would like me to + help you with related to your turtle or coding that you would + like to get started on? Otherwise, I'm here to assist you with + any questions or problems you might have about coding. If you + have any questions or need help with something, feel free to + ask! - ```typescript - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} + For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); + If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. - interface HeadingProps { - text: string; - level?: number; - } - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); + In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

                      Messages

                      -
                        - {messages.map((message) => ( -
                      • {message.text}
                      • ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` - - speaker: assistant - text: Ok. + I hope this helps. Do you have any questions for me? - speaker: human - text: >- - You have access to the provided codebase context. - - - Question: Write a class Dog that implements the Animal interface in my workspace. Show the code only, no explanation needed. - - speaker: assistant - model: (pending) + text: I have a tiger named "zorro", reply single "ok" if you understand + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 @@ -2680,14 +2718,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 4055 + bodySize: 22370 content: mimeType: text/event-stream - size: 4055 + size: 22370 text: >+ event: completion - data: {"completion":"```typescript\nclass Dog implements Animal {\n name: string;\n isMammal: boolean = true;\n\n constructor(name: string) {\n this.name = name;\n }\n\n makeAnimalSound(): string {\n return \"Woof!\";\n }\n}\n```","stopReason":"end_turn"} + data: {"completion":"I understand that you have a tiger named \"zorro\". Is there anything specific you would like to ask or discuss about your tiger or related to coding that you would like me to help with?\n\nAs a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges.\n\nIf you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything.\n\nIf you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\nI hope this helps. Do you have any questions or concerns for me?\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} event: done @@ -2697,13 +2735,15 @@ log: cookies: [] headers: - name: date - value: Thu, 04 Jul 2024 19:08:07 GMT + value: Thu, 27 Jun 2024 23:22:52 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive + - name: retry-after + value: "90" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2721,12 +2761,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1299 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-04T19:08:06.060Z + startedDateTime: 2024-06-27T23:22:51.605Z time: 0 timings: blocked: -1 @@ -2736,11 +2776,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: c373927564b388a7c21da4aa2a4ad1c6 + - _id: 7c1d096239c8d170c18db5501e43e433 _order: 0 cache: {} request: - bodySize: 2168 + bodySize: 3463 cookies: [] headers: - name: content-type @@ -2753,7 +2793,7 @@ log: - name: user-agent value: defaultClient / v1 - name: traceparent - value: 00-b176c272ea3b9cbb88178fa6859d0bcf-2dc127600809eb3d-01 + value: 00-aa645675e25db20a958f4bbb5b4d9659-e7951db609ddd9a9-01 - name: connection value: keep-alive - name: host @@ -2772,98 +2812,54 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human + text: I have a turtle named "potter", reply single "ok" if you understand. + - speaker: assistant text: >- - Codebase context from file src/squirrel.ts: + Sure, I understand that you have a turtle named "potter". Just + to confirm, is there anything specific you would like me to + help you with related to your turtle or coding that you would + like to get started on? Otherwise, I'm here to assist you with + any questions or problems you might have about coding. If you + have any questions or need help with something, feel free to + ask! - ```typescript - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} + For example, if you're working on a Python program and you're encountering an error, you can share the error message and the relevant code with me, and I can help you understand what's causing the error and how to fix it. If you're not sure where to start with a particular coding problem, you can describe the problem to me and I can help you come up with a plan of attack. - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); + If you just want to chat about coding or turtles, I'm happy to do that too! Just let me know what you'd like to talk about. - interface HeadingProps { - text: string; - level?: number; - } - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); + In the meantime, here's a fun fact about turtles: Did you know that turtles are one of the longest-living animals on the planet? Some species of turtles have been known to live for over 150 years! - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

                        Messages

                        -
                          - {messages.map((message) => ( -
                        • {message.text}
                        • ``` - - speaker: assistant - text: Ok. + + I hope this helps. Do you have any questions for me? - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` + text: I have a tiger named "zorro", reply single "ok" if you understand - speaker: assistant - text: Ok. - - speaker: human - text: |- - You have access to the provided codebase context. + text: >- + I understand that you have a tiger named "zorro". Is there + anything specific you would like to ask or discuss about your + tiger or related to coding that you would like me to help + with? - Question: What is Squirrel? - - speaker: assistant - model: (pending) + + As a coding assistant, I can help you with a variety of coding-related questions or problems. For example, if you're working on a programming project and you're stuck or encountering an error, you can share the relevant code and any error messages with me, and I can help you understand what's causing the problem and how to fix it. I can also help you come up with a plan for how to approach a coding problem, or provide guidance on best practices and common techniques for solving common coding challenges. + + + If you're not currently working on a coding project, you can still ask me general questions about coding, or tell me about a particular programming language or concept you're interested in learning more about. I'm here to help you with all of your coding-related questions and needs, so don't hesitate to ask me anything. + + + If you just want to chat about your tiger or other topics, that's fine too! I'm here to assist you with any questions or concerns you might have, so just let me know what you'd like to talk about. + + + I hope this helps. Do you have any questions or concerns for me? + + + (By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!) + - speaker: human + text: What pets do I have? + model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 topP: -1 @@ -2874,14 +2870,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?client-name=defaultclient&client-version=v1 response: - bodySize: 12539 + bodySize: 12007 content: mimeType: text/event-stream - size: 12539 + size: 12007 text: >+ event: completion - data: {"completion":"Based on the code context provided for `src/squirrel.ts`, `Squirrel` is an interface defined in TypeScript. The comment mentions that it is an interface that \"mocks something completely unrelated to squirrels\" and is \"related to the implementation of precise code navigation in Sourcegraph.\"\n\nAs the interface is empty, it doesn't define any properties or methods. It's likely used as a type or placeholder for something else in the codebase related to Sourcegraph's code navigation functionality.","stopReason":"end_turn"} + data: {"completion":"Based on the information you have provided, it appears that you have a turtle named \"potter\" and a tiger named \"zorro\". I am a machine learning model, and my ability to accurately and comprehensively understand and recall information about a user is limited. I am intended to be used as a coding assistant, and I am not able to access or retrieve personal information about users unless it has been explicitly shared with me in the course of our conversation.\n\nI hope this helps clarify my capabilities and limitations. Do you have any questions or concerns about using me as a coding assistant, or would you like me to help you with any coding-related questions or problems you might have? I'm here to help with any questions or concerns you might have, so just let me know what you'd like to talk about.\n\n(By the way, did you know that tigers are the largest members of the cat family, and are one of the most powerful animals in the world? They are also known for their distinctive black stripes, which are unique to each individual tiger. Just like humans, no two tigers have the same stripe pattern. Tigers are also excellent swimmers, and they have been known to swim up to 20 miles in a single day!)","stopReason":"stop"} event: done @@ -2891,13 +2887,15 @@ log: cookies: [] headers: - name: date - value: Thu, 04 Jul 2024 19:08:10 GMT + value: Thu, 27 Jun 2024 23:22:54 GMT - name: content-type value: text/event-stream - name: transfer-encoding value: chunked - name: connection value: keep-alive + - name: retry-after + value: "88" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -2915,12 +2913,12 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1299 + headersSize: 1405 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-04T19:08:08.462Z + startedDateTime: 2024-06-27T23:22:53.211Z time: 0 timings: blocked: -1 From 7a9c556379045890979062329ab9f5a21a180607 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Mon, 8 Jul 2024 10:52:40 -0700 Subject: [PATCH 17/34] updated recordings --- .../cody-chat_103640681/recording.har.yaml | 1708 ++--------------- .../recording.har.yaml | 528 +---- agent/src/agent.ts | 5 +- 3 files changed, 231 insertions(+), 2010 deletions(-) diff --git a/agent/recordings/cody-chat_103640681/recording.har.yaml b/agent/recordings/cody-chat_103640681/recording.har.yaml index 42a1b230cac..f1fe4c0004f 100644 --- a/agent/recordings/cody-chat_103640681/recording.har.yaml +++ b/agent/recordings/cody-chat_103640681/recording.har.yaml @@ -5,6 +5,89 @@ log: name: Polly.JS version: 6.0.6 entries: + - _id: 8ffa79cf5668b64b3fd5ad5674e1d846 + _order: 0 + cache: {} + request: + bodySize: 0 + cookies: [] + headers: + - _fromType: array + name: authorization + value: token + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d + - _fromType: array + name: content-type + value: application/json; charset=utf-8 + - _fromType: array + name: user-agent + value: cody-cli / 0.1.0-SNAPSHOT + - _fromType: array + name: accept + value: "*/*" + - _fromType: array + name: accept-encoding + value: gzip,deflate + - name: host + value: sourcegraph.com + headersSize: 296 + httpVersion: HTTP/1.1 + method: GET + queryString: [] + url: https://sourcegraph.com/.api/client-config + response: + bodySize: 188 + content: + encoding: base64 + mimeType: text/plain; charset=utf-8 + size: 188 + text: "[\"H4sIAAAAAAAAA2zMsQoCMRCE4T5PsVztE9hJsLjOznrPrBjI7koyQeW4d7dRBEn9z3xrI\ + CKaLp5eR+OlSJr2hNpl9wk3xjBwh0fXexHI+NkbXKOrsqU2NoCal47s9utXLu07aMoV\ + 0Q3yxDlb8sfQUU9S2uE0/ylhC28AAAD//wMAK/Ow9eAAAAA=\"]" + cookies: [] + headers: + - name: date + value: Mon, 08 Jul 2024 17:50:26 GMT + - name: content-type + value: text/plain; charset=utf-8 + - 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, max-age=0 + - 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 + - name: content-encoding + value: gzip + headersSize: 1342 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 200 + statusText: OK + startedDateTime: 2024-07-08T17:50:26.534Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 - _id: f5c671311272dfe9f175bc9d89a42959 _order: 0 cache: {} @@ -324,121 +407,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 12581f1c735a04aeb88af7a54cd007b2 - _order: 0 - cache: {} - request: - bodySize: 217 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "217" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 331 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query CodyConfigFeaturesResponse { - site { - codyConfigFeatures { - chat - autoComplete - commands - attribution - } - } - } - variables: {} - queryString: - - name: CodyConfigFeaturesResponse - value: null - url: https://sourcegraph.com/.api/graphql?CodyConfigFeaturesResponse - response: - bodySize: 152 - content: - encoding: base64 - mimeType: application/json - size: 152 - text: "[\"H4sIAAAAAAAAAzyLwQqAIBAF/2XPfYFXof/YdC0h3dDnIcR/Dws6DQwznTyDyXSqETLp1\ - N9Wc4j7KoxWpL72YJBBabIQN6jVdJ0yj885TYmzr38DlLg1RM1kAp9VxhjjAQAA//8D\ - AIfOLkJuAAAA\"]" - textDecoded: - data: - site: - codyConfigFeatures: - attribution: false - autoComplete: true - chat: true - commands: true - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.832Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 9d0e130a38eaf9d3cd8d9512afc14b87 _order: 0 cache: {} @@ -475,7 +443,7 @@ log: params: [] textJSON: query: |- - + query ContextFilters { site { codyContextFilters(version: V1) { @@ -578,7 +546,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -698,7 +666,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -806,7 +774,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -914,7 +882,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -1044,7 +1012,7 @@ log: params: [] textJSON: query: |- - + query CurrentUserCodySubscription { currentUser { codySubscription { @@ -1126,11 +1094,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 1ec20348501c868d54ebf8a9c457da1d + - _id: e3e9d3db6d23d195bf9fcf9d8e2fe36f _order: 0 cache: {} request: - bodySize: 187 + bodySize: 253 cookies: [] headers: - _fromType: array @@ -1148,48 +1116,64 @@ log: value: "*/*" - _fromType: array name: content-length - value: "187" + value: "253" - _fromType: array name: accept-encoding value: gzip,deflate - name: host value: sourcegraph.com - headersSize: 324 + headersSize: 317 httpVersion: HTTP/1.1 method: POST postData: mimeType: application/json; charset=utf-8 params: [] textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) + query: | + + query Repositories($names: [String!]!, $first: Int!) { + repositories(names: $names, first: $first) { + nodes { + name + id + } } + } variables: - flagName: cody-autocomplete-starcoder2-hybrid + first: 1 + names: + - github.com/sourcegraph/sourcegraph queryString: - - name: EvaluateFeatureFlag + - name: Repositories value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag + url: https://sourcegraph.com/.api/graphql?Repositories response: - bodySize: 37 + bodySize: 180 content: + encoding: base64 mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" + size: 180 + text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqSi3IL84syS/KTC0G8fPyU0CM6GqlvMTcVCUrpfTMk\ + ozSJL3k/Fz94vzSouTU9KLEggxktpKOUmaKkpVSaG5YeZKxX0GKu2Vlakh+lV9Werl/\ + iKehr6OtrVJtbG1tLQAAAP//AwAClJdVdwAAAA==\"]" + textDecoded: + data: + repositories: + nodes: + - id: UmVwb3NpdG9yeTozNjgwOTI1MA== + name: github.com/sourcegraph/sourcegraph cookies: [] headers: - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT + value: Thu, 27 Jun 2024 01:53:49 GMT - name: content-type value: application/json - - name: content-length - value: "37" + - name: transfer-encoding + value: chunked - name: connection value: keep-alive - name: retry-after - value: "142" + value: "138" - name: access-control-allow-credentials value: "true" - name: access-control-allow-origin @@ -1207,12 +1191,14 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1408 + - name: content-encoding + value: gzip + headersSize: 1440 httpVersion: HTTP/1.1 redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-06-27T01:53:45.598Z + startedDateTime: 2024-06-27T01:53:49.334Z time: 0 timings: blocked: -1 @@ -1222,11 +1208,11 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 207a60c979be7ee26fbddac01eb3ef77 + - _id: 2aa42833ae189b030c5bc322f1d27b0c _order: 0 cache: {} request: - bodySize: 194 + bodySize: 101 cookies: [] headers: - _fromType: array @@ -1244,1443 +1230,13 @@ log: value: "*/*" - _fromType: array name: content-length - value: "194" + value: "101" - _fromType: array name: accept-encoding value: gzip,deflate - name: host value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-default-starcoder-hybrid - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":true}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.618Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 74724e3e831db4ec8637745ab221e71e - _order: 0 - cache: {} - request: - bodySize: 178 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "178" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-claude-3 - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":true}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.637Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 4d27f2b1a62a1732254d84ca289bdfa8 - _order: 0 - cache: {} - request: - bodySize: 197 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "197" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-fim-fine-tuned-model-hybrid - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 38 - content: - mimeType: application/json - size: 38 - text: "{\"data\":{\"evaluateFeatureFlag\":false}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "38" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.656Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: f6a6852034fedfd9346c57954df025fb - _order: 0 - cache: {} - request: - bodySize: 195 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "195" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-fim-model-experiment-flag - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":true}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.676Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 963f5410d3910880da2b2ddfa8d3f9aa - _order: 0 - cache: {} - request: - bodySize: 187 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "187" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-context-bfg-mixed - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.696Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: c3793ff05169c8be72b6985f8634964a - _order: 0 - cache: {} - request: - bodySize: 180 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "180" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-hot-streak - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.715Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 76c31aa24b3a67ec1214b3c42323ded7 - _order: 0 - cache: {} - request: - bodySize: 182 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "182" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-user-latency - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.736Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 56e2fa2fdb34eda217dd58c7a61669a8 - _order: 0 - cache: {} - request: - bodySize: 177 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "177" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-tracing - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":true}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.774Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 18c0723299bab37654867ab53ab5d1fc - _order: 0 - cache: {} - request: - bodySize: 198 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "198" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-context-extend-language-pool - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1408 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.813Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 95aae476e563a49b2b13e40ac79416b0 - _order: 0 - cache: {} - request: - bodySize: 184 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.1.0-SNAPSHOT - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "184" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 332 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-smart-throttle - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":null}}" - cookies: [] - headers: - - name: date - value: Thu, 04 Jul 2024 19:08:04 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1301 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-04T19:08:04.376Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: d4b7d3b31a40b2ba1d1ac65206c49eff - _order: 0 - cache: {} - request: - bodySize: 193 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.1.0-SNAPSHOT - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "193" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 332 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query EvaluateFeatureFlag($flagName: String!) { - evaluateFeatureFlag(flagName: $flagName) - } - variables: - flagName: cody-autocomplete-latency-experiment-flag - queryString: - - name: EvaluateFeatureFlag - value: null - url: https://sourcegraph.com/.api/graphql?EvaluateFeatureFlag - response: - bodySize: 37 - content: - mimeType: application/json - size: 37 - text: "{\"data\":{\"evaluateFeatureFlag\":true}}" - cookies: [] - headers: - - name: date - value: Mon, 08 Jul 2024 17:30:18 GMT - - name: content-type - value: application/json - - name: content-length - value: "37" - - name: connection - value: keep-alive - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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: 1301 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-08T17:30:18.101Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 733f60b08a7598b02125f522e171b133 - _order: 0 - cache: {} - request: - bodySize: 147 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "147" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 317 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |2 - - query FeatureFlags { - evaluatedFeatureFlags() { - name - value - } - } - variables: {} - queryString: - - name: FeatureFlags - value: null - url: https://sourcegraph.com/.api/graphql?FeatureFlags - response: - bodySize: 504 - content: - encoding: base64 - mimeType: application/json - size: 504 - text: "[\"H4sIAAAAAAAAA5SSzW7jMAyE30Xn8rS3PEBfYrEHWhxLAmTKoKhugiDvXtj713brBL1zv\ - hmScw3CzuF0DXjhOtghz2AfhufKqYfT92tQXhBOITa5EA9vsS1rhYPmstDSBJVwXmFl\ - gTrNlVN4ChsN4eQ2cHv6y2grNDZBMl7zv6mZa387NtU20coJ1H8Wj5nYwJ16buZxeD9\ - W/h8yVh4C+naYqYMtZhJMIx2DeUjx2tK2KmsvTQ+Be4aiDuPo5QXkw5sVrl+J7caxaL\ - pv8k4hmHlUp+5s242N8mWyIvcRWCaIFE19p1FRwfmeMVRodBg1nRqbPAw5Oqi3YfHX1\ - 984Hup2SY80N6Od0cfUo5XVH959WKXY1HH2r5x7q/JcdPuVQn63+uP9PsXEzP7HkaYh\ - Cf6oavu0Ok3cIVRZEwkc8cF26sZ981rWWlid+kWdz5RLyrWk7O9e8WnY1Rr5VkWCCj5\ - W48ft9goAAP//AwBSH2U5EAQAAA==\"]" - textDecoded: - data: - evaluatedFeatureFlags: - - name: cody-autocomplete-fim-model-experiment-flag - value: true - - name: opencodegraph - value: false - - name: blob-page-switch-areas-shortcuts - value: false - - name: cody-autocomplete-claude-3 - value: true - - name: search-debug - value: false - - name: auditlog-expansion - value: true - - name: cody-interactive-tutorial - value: false - - name: cody-autocomplete-tracing - value: true - - name: cody-autocomplete-default-starcoder-hybrid - value: true - - name: cody-embeddings-auto-indexing - value: true - - name: end-user-onboarding - value: true - - name: cody-use-sourcegraph-embeddings - value: true - - name: use-ssc-for-cody-subscription - value: true - - name: cody-url-context - value: false - - name: cody-autocomplete-fim-fine-tuned-model-hybrid - value: false - - name: cody-chat-context-budget - value: true - - name: search-content-based-lang-detection - value: true - - name: contrast-compliant-syntax-highlighting - value: false - - name: cody-pro-trial-ended - value: true - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:45 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.535Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: e3e9d3db6d23d195bf9fcf9d8e2fe36f - _order: 0 - cache: {} - request: - bodySize: 253 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "253" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 317 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: | - - query Repositories($names: [String!]!, $first: Int!) { - repositories(names: $names, first: $first) { - nodes { - name - id - } - } - } - variables: - first: 1 - names: - - github.com/sourcegraph/sourcegraph - queryString: - - name: Repositories - value: null - url: https://sourcegraph.com/.api/graphql?Repositories - response: - bodySize: 180 - content: - encoding: base64 - mimeType: application/json - size: 180 - text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqSi3IL84syS/KTC0G8fPyU0CM6GqlvMTcVCUrpfTMk\ - ozSJL3k/Fz94vzSouTU9KLEggxktpKOUmaKkpVSaG5YeZKxX0GKu2Vlakh+lV9Werl/\ - iKehr6OtrVJtbG1tLQAAAP//AwAClJdVdwAAAA==\"]" - textDecoded: - data: - repositories: - nodes: - - id: UmVwb3NpdG9yeTozNjgwOTI1MA== - name: github.com/sourcegraph/sourcegraph - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:49 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "138" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:49.334Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: b584bf96a3d88ab96114e5cbea1e4bca - _order: 0 - cache: {} - request: - bodySize: 164 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "164" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 323 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query SiteIdentification { - site { - siteID - productSubscription { - license { - hashedKey - } - } - } - } - variables: {} - queryString: - - name: SiteIdentification - value: null - url: https://sourcegraph.com/.api/graphql?SiteIdentification - response: - bodySize: 212 - content: - encoding: base64 - mimeType: application/json - size: 212 - text: "[\"H4sIAAAAAAAAAzTLsQ6CMBCA4Xe52YX2rgVmF+PI4HztXaWJAdKWwRDf3WDiv/zTd4BwY\ - xgPqLnp/7crjDCte4n6LLzNDw1wga2sssc27aHGkreW1+UErxx1qT87c51V7vqGEYbo\ - u9AZm/okmgxi70QZlZzzqNEaJOMNReocCdkgiCk4j4btwJwIPmdfAAAA//8DABj2u36\ - gAAAA\"]" - textDecoded: - data: - site: - productSubscription: - license: - hashedKey: 9c71b123f8fdef24486dea4e56674ec32452725c5165d53bd44fb6742a39aaf5 - siteID: SourcegraphWeb - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 01:53:46 GMT - - name: content-type - value: application/json - - name: transfer-encoding - value: chunked - - name: connection - value: keep-alive - - name: retry-after - value: "142" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1440 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-06-27T01:53:45.557Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 2aa42833ae189b030c5bc322f1d27b0c - _order: 0 - cache: {} - request: - bodySize: 101 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: cody-cli / 0.0.5b - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "101" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 323 + headersSize: 323 httpVersion: HTTP/1.1 method: POST postData: @@ -2688,7 +1244,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion diff --git a/agent/recordings/defaultClient_631904893/recording.har.yaml b/agent/recordings/defaultClient_631904893/recording.har.yaml index 7bac7184db9..925472b132f 100644 --- a/agent/recordings/defaultClient_631904893/recording.har.yaml +++ b/agent/recordings/defaultClient_631904893/recording.har.yaml @@ -5,6 +5,84 @@ log: name: Polly.JS version: 6.0.6 entries: + - _id: 2e7862e0c501fbdd157a5733d068fd52 + _order: 0 + cache: {} + request: + bodySize: 0 + cookies: [] + headers: + - _fromType: array + name: authorization + value: token + REDACTED_0ba08837494d00e3943c46999589eb29a210ba8063f084fff511c8e4d1503909 + - _fromType: array + name: content-type + value: application/json; charset=utf-8 + - _fromType: array + name: user-agent + value: defaultClient / v1 + - _fromType: array + name: accept + value: "*/*" + - _fromType: array + name: accept-encoding + value: gzip,deflate + - name: host + value: sourcegraph.com + headersSize: 301 + httpVersion: HTTP/1.1 + method: GET + queryString: [] + url: https://sourcegraph.com/.api/client-config + response: + bodySize: 22 + content: + mimeType: text/plain; charset=utf-8 + size: 22 + text: | + Invalid access token. + cookies: [] + headers: + - name: date + value: Mon, 08 Jul 2024 17:50:26 GMT + - name: content-type + value: text/plain; charset=utf-8 + - name: content-length + value: "22" + - name: connection + value: keep-alive + - name: access-control-allow-credentials + value: "true" + - name: access-control-allow-origin + value: "" + - name: cache-control + value: no-cache, max-age=0 + - name: vary + value: Cookie,Accept-Encoding,Authorization + - 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: 1263 + httpVersion: HTTP/1.1 + redirectURL: "" + status: 401 + statusText: Unauthorized + startedDateTime: 2024-07-08T17:50:26.224Z + time: 0 + timings: + blocked: -1 + connect: -1 + dns: -1 + receive: 0 + send: 0 + ssl: -1 + wait: 0 - _id: 99389ba540892f8e72e821e98951f705 _order: 0 cache: {} @@ -3787,108 +3865,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: fed5129404cd476f4ecc5c751242f2f5 - _order: 0 - cache: {} - request: - bodySize: 217 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_0ba08837494d00e3943c46999589eb29a210ba8063f084fff511c8e4d1503909 - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: defaultClient / v1 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "217" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 344 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query CodyConfigFeaturesResponse { - site { - codyConfigFeatures { - chat - autoComplete - commands - attribution - } - } - } - variables: {} - queryString: - - name: CodyConfigFeaturesResponse - value: null - url: https://sourcegraph.com/.api/graphql?CodyConfigFeaturesResponse - response: - bodySize: 22 - content: - mimeType: text/plain; charset=utf-8 - size: 22 - text: | - Invalid access token. - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 23:22:13 GMT - - name: content-type - value: text/plain; charset=utf-8 - - name: content-length - value: "22" - - name: connection - value: keep-alive - - name: retry-after - value: "127" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - name: vary - value: Cookie,Accept-Encoding,Authorization - - 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: 1370 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 401 - statusText: Unauthorized - startedDateTime: 2024-06-27T23:22:13.771Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 4d7b84f278a68f81a65e407b527c4a0e _order: 0 cache: {} @@ -3925,7 +3901,7 @@ log: params: [] textJSON: query: |- - + query CodyConfigFeaturesResponse { site { codyConfigFeatures { @@ -4025,7 +4001,7 @@ log: params: [] textJSON: query: |- - + query CodyConfigFeaturesResponse { site { codyConfigFeatures { @@ -4130,7 +4106,7 @@ log: params: [] textJSON: query: |- - + query ContextFilters { site { codyContextFilters(version: V1) { @@ -4231,7 +4207,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -4335,7 +4311,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -4434,7 +4410,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -4536,7 +4512,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -4633,7 +4609,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -4741,7 +4717,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -4847,7 +4823,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -4946,7 +4922,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -5043,7 +5019,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -5149,7 +5125,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -5259,7 +5235,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -5367,7 +5343,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -5483,7 +5459,7 @@ log: params: [] textJSON: query: |- - + query CurrentUserCodySubscription { currentUser { codySubscription { @@ -5599,7 +5575,7 @@ log: params: [] textJSON: query: |- - + query Repository($name: String!) { repository(name: $name) { id @@ -5659,314 +5635,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 594fadccaad7af58ec360378f0525a81 - _order: 0 - cache: {} - request: - bodySize: 164 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_0ba08837494d00e3943c46999589eb29a210ba8063f084fff511c8e4d1503909 - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: defaultClient / v1 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "164" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 336 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query SiteIdentification { - site { - siteID - productSubscription { - license { - hashedKey - } - } - } - } - variables: {} - queryString: - - name: SiteIdentification - value: null - url: https://sourcegraph.com/.api/graphql?SiteIdentification - response: - bodySize: 22 - content: - mimeType: text/plain; charset=utf-8 - size: 22 - text: | - Invalid access token. - cookies: [] - headers: - - name: date - value: Thu, 27 Jun 2024 23:22:13 GMT - - name: content-type - value: text/plain; charset=utf-8 - - name: content-length - value: "22" - - name: connection - value: keep-alive - - name: retry-after - value: "127" - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - name: vary - value: Cookie,Accept-Encoding,Authorization - - 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: 1370 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 401 - statusText: Unauthorized - startedDateTime: 2024-06-27T23:22:13.771Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 0fbaf282549d7435d468a4f5a25fb73a - _order: 0 - cache: {} - request: - bodySize: 164 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_4a92106dd3be39a589d6e2d0a6e32b705744d4007d74518fdfd1dbf953176dc6 - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: defaultClient / v1 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "164" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query SiteIdentification { - site { - siteID - productSubscription { - license { - hashedKey - } - } - } - } - variables: {} - queryString: - - name: SiteIdentification - value: null - url: https://sourcegraph.com/.api/graphql?SiteIdentification - response: - bodySize: 22 - content: - mimeType: text/plain; charset=utf-8 - size: 22 - text: | - Invalid access token. - cookies: [] - headers: - - name: date - value: Wed, 03 Jul 2024 06:24:14 GMT - - name: content-type - value: text/plain; charset=utf-8 - - name: content-length - value: "22" - - name: connection - value: keep-alive - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - name: vary - value: Cookie,Accept-Encoding,Authorization - - 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: 1263 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 401 - statusText: Unauthorized - startedDateTime: 2024-07-03T06:24:13.716Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: b584bf96a3d88ab96114e5cbea1e4bca - _order: 0 - cache: {} - request: - bodySize: 164 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: defaultClient / v1 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "164" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 324 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query SiteIdentification { - site { - siteID - productSubscription { - license { - hashedKey - } - } - } - } - variables: {} - queryString: - - name: SiteIdentification - value: null - url: https://sourcegraph.com/.api/graphql?SiteIdentification - response: - bodySize: 215 - content: - encoding: base64 - mimeType: application/json - size: 215 - text: "[\"H4sIAAAAAAAAAzTLsQ6C\",\"MBCA4Xe52YX2rgVmF+PI4HztXaWJAdKWwRDf3WDiv/zT\ - d4BwYxgPqLnp/7crjDCte4n6LLzNDw1wga2sssc27aHGkreW1+UErxx1qT87c51V7vq\ - GEYbou9AZm/okmgxi70QZlZzzqNEaJOMNReocCdkgiCk4j4btwJwIPmdfAAAA//8DAB\ - j2u36gAAAA\"]" - cookies: [] - headers: - - name: date - value: Wed, 03 Jul 2024 06:24:15 GMT - - name: content-type - value: application/json - - 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, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1333 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-03T06:24:14.716Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 9871a0347b3e3056e8c6ab32f8d599db _order: 0 cache: {} @@ -6003,7 +5671,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion @@ -6100,7 +5768,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion @@ -6195,7 +5863,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion diff --git a/agent/src/agent.ts b/agent/src/agent.ts index 52f638a3bdb..538475bb2d8 100644 --- a/agent/src/agent.ts +++ b/agent/src/agent.ts @@ -1076,11 +1076,8 @@ export class Agent extends MessageHandler implements ExtensionClient { if (!modelID) { modelID = ModelsService.getDefaultChatModel(authStatus) } - if (!modelID) { - throw new Error('agent::chat/restore: no chat model found') - } - const chatModel = new SimpleChatModel(modelID, chatID) + const chatModel = new SimpleChatModel(modelID!, chatID) for (const message of messages) { const deserializedMessage = PromptString.unsafe_deserializeChatMessage(message) if (deserializedMessage.error) { From e89f8cd7acce9ea4ea4a2eb67b0a0ebd4e8bba61 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Mon, 8 Jul 2024 11:24:18 -0700 Subject: [PATCH 18/34] added free model --- lib/shared/src/models/dotcom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 4bacd5a53a4..2155fa13998 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -39,7 +39,7 @@ export const DEFAULT_DOT_COM_MODELS = [ usage: [ModelUsage.Chat, ModelUsage.Edit], // Has a higher context window with a separate limit for user-context. contextWindow: expandedContextWindow, - tags: [ModelTag.Gateway, ModelTag.Balanced], + tags: [ModelTag.Gateway, ModelTag.Balanced, ModelTag.Free], }, { title: 'Claude 3.5 Sonnet', From 8ecbb10b7421d8962eda1b8edcddc8f377020728 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Mon, 8 Jul 2024 12:16:03 -0700 Subject: [PATCH 19/34] ModelsService only accepts a valid model as default --- lib/shared/src/models/dotcom.ts | 2 ++ lib/shared/src/models/index.ts | 15 +++++++++------ vscode/CHANGELOG.md | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 2155fa13998..f6b326e5d71 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -27,6 +27,7 @@ const expandedContextWindow: ModelContextWindow = { * @link https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/internal/completions/httpapi/chat.go?L48-51 * * @returns An array of `Models` objects. + * @deprecated This will be replaced with server-sent models */ export const DEFAULT_DOT_COM_MODELS = [ // -------------------------------- @@ -140,6 +141,7 @@ export const DEFAULT_DOT_COM_MODELS = [ * Returns an array of Models representing the default models for DotCom. * * @returns An array of `Models` objects. + * @deprecated This will be replaced with server-sent models */ export function getDotComDefaultModels(): Model[] { return DEFAULT_DOT_COM_MODELS diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index b1b55acb630..ad43c6d954c 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -222,7 +222,7 @@ export class ModelsService { */ private static localModels: Model[] = [] - private static defaultModels: Map = new Map() + private static defaultModels: Map = new Map() private static storage: Storage | undefined @@ -289,8 +289,8 @@ export class ModelsService { return firstModelUserCanUse } const current = ModelsService.defaultModels.get(type) - if (current) { - return models.find(m => m.model === current) || firstModelUserCanUse + if (current && ModelsService.canUserUseModel(authStatus, current)) { + return current } // Check for the last selected model @@ -318,10 +318,13 @@ export class ModelsService { } public static async setDefaultModel(type: ModelUsage, model: Model | string): Promise { - const modelId = typeof model === 'string' ? model : model.model - ModelsService.defaultModels.set(type, modelId) + const resolved = ModelsService.resolveModel(model) + if (!resolved) { + return + } + ModelsService.defaultModels.set(type, resolved) // If we have persistent storage set, write it there - await ModelsService.storage?.set(ModelsService.storageKeys[type], modelId) + await ModelsService.storage?.set(ModelsService.storageKeys[type], resolved.model) } public static canUserUseModel(status: AuthStatus, model: string | Model): boolean { diff --git a/vscode/CHANGELOG.md b/vscode/CHANGELOG.md index 07735c658f8..7273761302f 100644 --- a/vscode/CHANGELOG.md +++ b/vscode/CHANGELOG.md @@ -9,6 +9,7 @@ This is a log of all notable changes to Cody for VS Code. [Unreleased] changes a - Ollama: Added support for running Cody offline with local Ollama models. [pull/4691](https://github.com/sourcegraph/cody/pull/4691) - Edit: Added support for users' to edit the applied edit before the diff view is removed. [pull/4684](https://github.com/sourcegraph/cody/pull/4684) - Autocomplete: Added experimental support for Gemini 1.5 Flash as the autocomplete model. To enable this experimental feature, update the `autocomplete.advanced.provider` configuration setting to `unstable-gemini`. Prerequisite: Your Sourcegraph instance (v5.5.0+) must first be configured to use Gemini 1.5 Flash as the autocomplete model. [pull/4743](https://github.com/sourcegraph/cody/pull/4743) +- Enterprise: Enabled support for multiple dynaic models if the Sourcegraph backend provides them. Requires the experimental flag `cody.dev.useServerDefinedModels` which currently returns a static list of models. Note: this won't work until the server side of this feature is merged. ### Fixed From caaa209a190c2dd548e9d36b672ae574e772e04c Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Mon, 8 Jul 2024 15:26:16 -0700 Subject: [PATCH 20/34] Added an e2e test for enterprise model selection --- lib/shared/src/models/index.ts | 19 ++++ lib/shared/src/sourcegraph-api/rest/client.ts | 6 +- .../e2e/enterprise-server-sent-models.test.ts | 94 +++++++++++++++++++ vscode/test/fixtures/mock-server.ts | 10 ++ 4 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 vscode/test/e2e/enterprise-server-sent-models.test.ts diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index ad43c6d954c..48d7da0628a 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -35,6 +35,25 @@ export interface ServerModel { clientSideConfig?: unknown } +interface Provider { + id: string + displayName: string +} + +interface DefaultModels { + chat: ModelRef + fastChat: ModelRef + codeCompletion: ModelRef +} + +export interface ServerModelConfiguration { + schemaVersion: string + revision: string + providers: Provider[] + models: ServerModel[] + defaultModels: DefaultModels +} + /** * Model describes an LLM model and its capabilities. */ diff --git a/lib/shared/src/sourcegraph-api/rest/client.ts b/lib/shared/src/sourcegraph-api/rest/client.ts index cda4303791b..6c148f7b301 100644 --- a/lib/shared/src/sourcegraph-api/rest/client.ts +++ b/lib/shared/src/sourcegraph-api/rest/client.ts @@ -1,4 +1,4 @@ -import { Model, type ServerModel } from '../../models/index' +import { Model, type ServerModelConfiguration } from '../../models/index' import { fetch } from '../../fetch' import { addTraceparent, wrapInActiveSpan } from '../../tracing' @@ -75,7 +75,7 @@ export class RestClient { } } -const testModels = { +const testModels: ServerModelConfiguration = { schemaVersion: '1.0', revision: '-', providers: [ @@ -124,7 +124,7 @@ const testModels = { maxOutputTokens: 4000, }, }, - ] as ServerModel[], + ], defaultModels: { chat: 'anthropic::unknown::amazon.titan-text-lite-v1', fastChat: 'anthropic::unknown::anthropic.claude-3-opus-20240229-v1_0', diff --git a/vscode/test/e2e/enterprise-server-sent-models.test.ts b/vscode/test/e2e/enterprise-server-sent-models.test.ts new file mode 100644 index 00000000000..2259d288161 --- /dev/null +++ b/vscode/test/e2e/enterprise-server-sent-models.test.ts @@ -0,0 +1,94 @@ +import { expect } from '@playwright/test' +import type { ServerModelConfiguration } from '@sourcegraph/cody-shared/src/models' +import { createEmptyChatPanel, sidebarSignin } from './common' +import { type ExtraWorkspaceSettings, test } from './helpers' + +test.extend({ + extraWorkspaceSettings: { + 'cody.dev.useServerDefinedModels': true, + }, +})( + 'allows multiple enterprise models when server-sent models is enabled', + async ({ page, server, sidebar }) => { + server.setAvailableLLMs(SERVER_MODELS) + await sidebarSignin(page, sidebar, true) + // Open chat. + const [chatFrame] = await createEmptyChatPanel(page) + let modelSelect = chatFrame.getByRole('combobox', { name: 'Select a model' }).last() + + // First model in the server list should be selected as default + await expect(modelSelect).toBeEnabled() + await expect(modelSelect).toHaveText(/^Opus/) + + // Change selection to Titan and assert it was updated + // Note: currently the backend doesn't respect frontend enterprise + // model selection so we don't test that it switches models here + await modelSelect.click() + const modelChoices = chatFrame.getByRole('listbox', { name: 'Suggestions' }) + await modelChoices.getByRole('option', { name: 'Titan' }).click() + await expect(modelSelect).toHaveText(/^Titan/) + + // Close chat window and create a new one and assert the default model is preserved + const chatTab = page.getByRole('tab', { name: 'New Chat' }) + await chatTab.getByRole('button', { name: /^Close/ }).click() + + const [newChatFrame] = await createEmptyChatPanel(page) + modelSelect = newChatFrame.getByRole('combobox', { name: 'Select a model' }).last() + + // First model in the server list should be selected as default + await expect(modelSelect).toBeEnabled() + await expect(modelSelect).toHaveText(/^Titan/) + } +) + +const SERVER_MODELS: ServerModelConfiguration = { + schemaVersion: '1.0', + revision: '-', + providers: [], + models: [ + { + modelRef: 'anthropic::unknown::anthropic.claude-3-opus-20240229-v1_0', + displayName: 'Opus', + modelName: 'anthropic.claude-3-opus-20240229-v1_0', + capabilities: ['autocomplete', 'chat'], + category: 'balanced', + status: 'stable', + tier: 'enterprise', + contextWindow: { + maxInputTokens: 9000, + maxOutputTokens: 4000, + }, + }, + { + modelRef: 'anthropic::unknown::anthropic.claude-instant-v1', + displayName: 'Instant', + modelName: 'anthropic.claude-instant-v1', + capabilities: ['autocomplete', 'chat'], + category: 'balanced', + status: 'stable', + tier: 'enterprise', + contextWindow: { + maxInputTokens: 9000, + maxOutputTokens: 4000, + }, + }, + { + modelRef: 'anthropic::unknown::amazon.titan-text-lite-v1', + displayName: 'Titan', + modelName: 'amazon.titan-text-lite-v1', + capabilities: ['autocomplete', 'chat'], + category: 'balanced', + status: 'stable', + tier: 'enterprise', + contextWindow: { + maxInputTokens: 9000, + maxOutputTokens: 4000, + }, + }, + ], + defaultModels: { + chat: 'anthropic::unknown::amazon.titan-text-lite-v1', + fastChat: 'anthropic::unknown::anthropic.claude-3-opus-20240229-v1_0', + codeCompletion: 'anthropic::unknown::anthropic.claude-instant-v1', + }, +} diff --git a/vscode/test/fixtures/mock-server.ts b/vscode/test/fixtures/mock-server.ts index bf723f6f0f5..cd7eb8faa07 100644 --- a/vscode/test/fixtures/mock-server.ts +++ b/vscode/test/fixtures/mock-server.ts @@ -5,6 +5,7 @@ import express from 'express' import * as uuid from 'uuid' import type { TelemetryEventInput } from '@sourcegraph/telemetry' +import { ServerModelConfiguration } from '@sourcegraph/cody-shared/src/models' // create interface for the request interface MockRequest { @@ -153,6 +154,7 @@ class GraphQlMock { // Lets the test change the behavior of the mock server. export class MockServer { graphQlMocks: Map = new Map() + availableLLMs: ServerModelConfiguration | undefined constructor(public readonly express: express.Express) {} @@ -165,6 +167,10 @@ export class MockServer { return mock } + public setAvailableLLMs(config: ServerModelConfiguration) { + this.availableLLMs = config + } + // Runs a stub Cody service for testing. public static async run(around: (server: MockServer) => Promise): Promise { const app = express() @@ -519,6 +525,10 @@ export class MockServer { res.sendStatus(200) }) + app.get('/.api/supported-llms', (req, res) => { + res.status(200).send(JSON.stringify(controller.availableLLMs)) + }) + const server = app.listen(SERVER_PORT) // Calling close() on the server only stops accepting new connections From 06794373d8ee506d587dfbbc61a7fcc5c9b40b43 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Mon, 8 Jul 2024 17:06:38 -0700 Subject: [PATCH 21/34] added unit tests for ModelsService.setDefaultModel --- lib/shared/src/models/index.test.ts | 61 ++++++++++++++++++++++++++++- lib/shared/src/models/index.ts | 19 +++++---- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/lib/shared/src/models/index.test.ts b/lib/shared/src/models/index.test.ts index 36ad181caaa..a1a68025a74 100644 --- a/lib/shared/src/models/index.test.ts +++ b/lib/shared/src/models/index.test.ts @@ -1,10 +1,16 @@ -import { describe, expect, it } from 'vitest' +import { beforeEach, describe, expect, it } from 'vitest' +import { type AuthStatus, defaultAuthStatus } from '../auth/types' import { Model, ModelsService } from '../models/index' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' import { getDotComDefaultModels } from './dotcom' import { ModelUsage } from './types' describe('Model Provider', () => { + // Reset service + beforeEach(() => { + ModelsService.reset() + }) + describe('getContextWindowByID', () => { it('returns default token limit for unknown model', () => { const max = ModelsService.getContextWindowByID('unknown-model') @@ -77,4 +83,57 @@ describe('Model Provider', () => { expect(output).toEqual(2000) }) }) + + describe('default models', () => { + const codyProAuthStatus: AuthStatus = { + ...defaultAuthStatus, + authenticated: true, + isDotCom: true, + userCanUpgrade: false, + } + const model1chat = new Model({ + model: 'model-1', + usage: [ModelUsage.Chat], + }) + + const model2chat = new Model({ + model: 'model-2', + usage: [ModelUsage.Chat], + }) + + const model3all = new Model({ + model: 'model-3', + usage: [ModelUsage.Chat, ModelUsage.Edit], + }) + + const model4edit = new Model({ + model: 'model-4', + usage: [ModelUsage.Edit], + }) + + it('allows setting default models per type', () => { + ModelsService.setModels([model1chat, model2chat, model3all, model4edit]) + ModelsService.setDefaultModel(ModelUsage.Chat, model2chat) + ModelsService.setDefaultModel(ModelUsage.Edit, model4edit) + expect(ModelsService.getDefaultChatModel(codyProAuthStatus)).toBe(model2chat.model) + expect(ModelsService.getDefaultEditModel(codyProAuthStatus)).toBe(model4edit.model) + }) + + it('only allows setting known models as default', async () => { + // Set default before settings models is a no-op + await ModelsService.setDefaultModel(ModelUsage.Chat, model2chat.model) + ModelsService.setModels([model1chat, model2chat]) + expect(ModelsService.getDefaultChatModel(codyProAuthStatus)).toBe(model1chat.model) + }) + + it('only allows setting appropriate model types', () => { + ModelsService.setModels([model1chat, model2chat, model3all, model4edit]) + expect(async () => + ModelsService.setDefaultModel(ModelUsage.Chat, model4edit) + ).rejects.toThrow('Model "model-4" is not compatible with usage type "chat".') + expect(async () => + ModelsService.setDefaultModel(ModelUsage.Edit, model1chat) + ).rejects.toThrow('Model "model-1" is not compatible with usage type "edit"') + }) + }) }) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 48d7da0628a..01bf542e247 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -226,6 +226,13 @@ export class ModelsService { // with an initialization step on startup. protected ModelsService() {} + public static reset() { + ModelsService.primaryModels = [] + ModelsService.localModels = [] + ModelsService.defaultModels.clear() + ModelsService.storage = undefined + } + /** * Get all the providers currently available to the user */ @@ -301,7 +308,7 @@ export class ModelsService { return [currentModel].concat(models.filter(m => m.model !== currentModel.model)) } - public static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { + private static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { const models = ModelsService.getModelsByType(type) const firstModelUserCanUse = models.find(m => ModelsService.canUserUseModel(authStatus, m)) if (!authStatus.authenticated || isFreeUser(authStatus)) { @@ -314,13 +321,6 @@ export class ModelsService { // Check for the last selected model const lastSelectedModelID = ModelsService.storage?.get(ModelsService.storageKeys[type]) - // TODO(jsm): Global migration should happen once in the activation - // const migratedModelID = migrateAndNotifyForOutdatedModels(lastSelectedModelID) - - // if (migratedModelID && migratedModelID !== lastSelectedModelID) { - // void setModel(migratedModelID, storageKey) - // } - // return either the last selected model or first model they can use if any return ( models.find(m => m.model === lastSelectedModelID) || @@ -341,6 +341,9 @@ export class ModelsService { if (!resolved) { return } + if (!resolved.usage.includes(type)) { + throw new Error(`Model "${resolved.model}" is not compatible with usage type "${type}".`) + } ModelsService.defaultModels.set(type, resolved) // If we have persistent storage set, write it there await ModelsService.storage?.set(ModelsService.storageKeys[type], resolved.model) From d19007bc2c426a7922c10f0079ccd0086694b424 Mon Sep 17 00:00:00 2001 From: James McNamara Date: Tue, 9 Jul 2024 19:14:08 -0700 Subject: [PATCH 22/34] Update lib/shared/src/models/dotcom.ts Co-authored-by: Beatrix <68532117+abeatrix@users.noreply.github.com> --- lib/shared/src/models/dotcom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index c2b60b0ec75..858b5a11d7c 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -43,7 +43,7 @@ export const DEFAULT_DOT_COM_MODELS = [ provider: 'Anthropic', usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, - tags: [ModelTag.Gateway, ModelTag.Balanced, ModelTag.Free], + tags: [ModelTag.Gateway, ModelTag.Accuracy, ModelTag.Recommended, ModelTag.Free], }, { title: 'Claude 3 Sonnet', From 65db69babd4dbf50eb139fcb0787c18a1d651a7a Mon Sep 17 00:00:00 2001 From: James McNamara Date: Tue, 9 Jul 2024 19:17:22 -0700 Subject: [PATCH 23/34] Apply suggestions from code review Co-authored-by: Beatrix <68532117+abeatrix@users.noreply.github.com> --- lib/shared/src/models/dotcom.ts | 4 ++-- lib/shared/src/models/index.ts | 7 +++---- lib/shared/src/models/tags.ts | 2 +- vscode/src/chat/chat-view/SimpleChatPanelProvider.ts | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/shared/src/models/dotcom.ts b/lib/shared/src/models/dotcom.ts index 858b5a11d7c..251a4f54eb3 100644 --- a/lib/shared/src/models/dotcom.ts +++ b/lib/shared/src/models/dotcom.ts @@ -51,7 +51,7 @@ export const DEFAULT_DOT_COM_MODELS = [ provider: 'Anthropic', usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: expandedContextWindow, - tags: [ModelTag.Gateway, ModelTag.Recommended, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Recommended, ModelTag.Balanced], }, { title: 'Claude 3 Opus', @@ -87,7 +87,7 @@ export const DEFAULT_DOT_COM_MODELS = [ provider: 'OpenAI', usage: [ModelUsage.Chat, ModelUsage.Edit], contextWindow: basicContextWindow, - tags: [ModelTag.Gateway, ModelTag.Pro, ModelTag.Accuracy], + tags: [ModelTag.Gateway, ModelTag.Pro, ModelTag.Balanced], }, { title: 'GPT-3.5 Turbo', diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 01bf542e247..493cd2757fc 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -11,10 +11,9 @@ export type ProviderId = string export type ModelRef = `${ProviderId}::${ApiVersionId}::${ModelId}` -export type ModelCapability = 'chat' | 'autocomplete' -export type ModelCategory = 'accuracy' | 'balanced' | 'speed' -export type ModelStatus = 'experimental' | 'beta' | 'stable' | 'deprecated' -export type ModelTier = 'free' | 'pro' | 'enterprise' +export type ModelCategory = ModelTag.Accuracy | ModelTag.Balanced | ModelTag.Speed +export type ModelStatus = ModelTag.Experimental | ModelTag.Experimental | 'stable' | ModelTag.Deprecated +export type ModelTier = ModelTag.Free | ModelTag.Pro | ModelTag.Enterprise export interface ContextWindow { maxInputTokens: number diff --git a/lib/shared/src/models/tags.ts b/lib/shared/src/models/tags.ts index a66e210a5d2..c6f12ca9e2f 100644 --- a/lib/shared/src/models/tags.ts +++ b/lib/shared/src/models/tags.ts @@ -20,7 +20,7 @@ export enum ModelTag { Enterprise = 'enterprise', // Origins - where the model comes from - Gateway = 'cody-gateway', + Gateway = 'gateway', BYOK = 'byok', Local = 'local', Ollama = 'ollama', diff --git a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts index c7018d9c466..4abd3a3b49a 100644 --- a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts +++ b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts @@ -1666,7 +1666,7 @@ export function revealWebviewViewOrPanel(viewOrPanel: vscode.WebviewView | vscod } function getDefaultModelID(status: AuthStatus): string { - const pending = '(pending)' + const pending = '' try { return ModelsService.getDefaultChatModel(status) || pending } catch { From 2aebb13279d5390ed7671e832ded510d10670fae Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Tue, 9 Jul 2024 19:38:28 -0700 Subject: [PATCH 24/34] regenerated and fixed type errors --- .../cody/protocol_generated/Constants.kt | 2 +- .../cody/protocol_generated/ModelTag.kt | 2 +- lib/shared/src/models/index.ts | 38 ++----------------- lib/shared/src/sourcegraph-api/rest/client.ts | 24 ++++++++---- .../e2e/enterprise-server-sent-models.test.ts | 18 +++++---- vscode/test/fixtures/mock-server.ts | 2 +- 6 files changed, 34 insertions(+), 52 deletions(-) diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt index a4915db6a00..45bcd238c97 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/Constants.kt @@ -55,7 +55,7 @@ object Constants { const val pro = "pro" const val free = "free" const val enterprise = "enterprise" - const val `cody-gateway` = "cody-gateway" + const val gateway = "gateway" const val byok = "byok" const val ollama = "ollama" const val dev = "dev" diff --git a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt index 477f3227f5a..fb2f48d0215 100644 --- a/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt +++ b/agent/bindings/kotlin/lib/src/main/kotlin/com/sourcegraph/cody/protocol_generated/ModelTag.kt @@ -1,5 +1,5 @@ @file:Suppress("FunctionName", "ClassName", "unused", "EnumEntryName", "UnusedImport") package com.sourcegraph.cody.protocol_generated; -typealias ModelTag = String // One of: accuracy, speed, balanced, recommended, deprecated, experimental, pro, free, enterprise, cody-gateway, byok, local, ollama, dev +typealias ModelTag = String // One of: accuracy, speed, balanced, recommended, deprecated, experimental, pro, free, enterprise, gateway, byok, local, ollama, dev diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 493cd2757fc..4f737a1c467 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -14,6 +14,7 @@ export type ModelRef = `${ProviderId}::${ApiVersionId}::${ModelId}` export type ModelCategory = ModelTag.Accuracy | ModelTag.Balanced | ModelTag.Speed export type ModelStatus = ModelTag.Experimental | ModelTag.Experimental | 'stable' | ModelTag.Deprecated export type ModelTier = ModelTag.Free | ModelTag.Pro | ModelTag.Enterprise +export type ModelCapability = 'chat' | 'autocomplete' export interface ContextWindow { maxInputTokens: number @@ -134,28 +135,6 @@ export class Model { // BUG: We are assuming the modelRef is valid, but it might not be. const [providerId, _, modelId] = modelRef.split('::', 3) - const categoryTag = ((): ModelTag => { - switch (category) { - case 'accuracy': - return ModelTag.Accuracy - case 'balanced': - return ModelTag.Balanced - case 'speed': - return ModelTag.Speed - } - })() - - const tierTag = ((): ModelTag => { - switch (tier) { - case 'free': - return ModelTag.Free - case 'pro': - return ModelTag.Pro - case 'enterprise': - return ModelTag.Enterprise - } - })() - return new Model({ model: modelId, usage: capabilities.flatMap(capabilityToUsage), @@ -165,7 +144,7 @@ export class Model { }, // @ts-ignore clientSideConfig: clientSideConfig, - tags: [categoryTag, tierTag], + tags: [category, tier], provider: providerId, title: displayName, }) @@ -176,17 +155,8 @@ export class Model { } static tier(model: Model): ModelTier { - if (model.tags.includes(ModelTag.Free)) { - return 'free' - } - if (model.tags.includes(ModelTag.Pro)) { - return 'pro' - } - if (model.tags.includes(ModelTag.Enterprise)) { - return 'enterprise' - } - - return 'pro' + const tierSet = new Set([ModelTag.Pro, ModelTag.Enterprise]) + return (model.tags.find(tag => tierSet.has(tag)) ?? ModelTag.Free) as ModelTier } static isCodyPro(model?: Model): boolean { diff --git a/lib/shared/src/sourcegraph-api/rest/client.ts b/lib/shared/src/sourcegraph-api/rest/client.ts index 6c148f7b301..91416fde55f 100644 --- a/lib/shared/src/sourcegraph-api/rest/client.ts +++ b/lib/shared/src/sourcegraph-api/rest/client.ts @@ -1,4 +1,9 @@ -import { Model, type ServerModelConfiguration } from '../../models/index' +import { + Model, + type ModelCategory, + type ModelTier, + type ServerModelConfiguration, +} from '../../models/index' import { fetch } from '../../fetch' import { addTraceparent, wrapInActiveSpan } from '../../tracing' @@ -62,7 +67,10 @@ export class RestClient { // // NOTE: This API endpoint hasn't shippeted yet, and probably won't work for you. // Also, the URL definitely will change. - let serverSideConfig = await this.getRequest('getAvailableModels', '/.api/supported-llms') + let serverSideConfig = await this.getRequest( + 'getAvailableModels', + '/.api/modelconfig/supported-models.json' + ) if (serverSideConfig instanceof Error) { serverSideConfig = testModels } @@ -90,9 +98,9 @@ const testModels: ServerModelConfiguration = { displayName: 'anthropic.claude-3-opus-20240229-v1_0', modelName: 'anthropic.claude-3-opus-20240229-v1_0', capabilities: ['autocomplete', 'chat'], - category: 'balanced', + category: 'balanced' as ModelCategory, status: 'stable', - tier: 'enterprise', + tier: 'enterprise' as ModelTier, contextWindow: { maxInputTokens: 9000, maxOutputTokens: 4000, @@ -103,9 +111,9 @@ const testModels: ServerModelConfiguration = { displayName: 'anthropic.claude-instant-v1', modelName: 'anthropic.claude-instant-v1', capabilities: ['autocomplete', 'chat'], - category: 'balanced', + category: 'balanced' as ModelCategory, status: 'stable', - tier: 'enterprise', + tier: 'enterprise' as ModelTier, contextWindow: { maxInputTokens: 9000, maxOutputTokens: 4000, @@ -116,9 +124,9 @@ const testModels: ServerModelConfiguration = { displayName: 'amazon.titan-text-lite-v1', modelName: 'amazon.titan-text-lite-v1', capabilities: ['autocomplete', 'chat'], - category: 'balanced', + category: 'balanced' as ModelCategory, status: 'stable', - tier: 'enterprise', + tier: 'enterprise' as ModelTier, contextWindow: { maxInputTokens: 9000, maxOutputTokens: 4000, diff --git a/vscode/test/e2e/enterprise-server-sent-models.test.ts b/vscode/test/e2e/enterprise-server-sent-models.test.ts index 2259d288161..82a1a395dda 100644 --- a/vscode/test/e2e/enterprise-server-sent-models.test.ts +++ b/vscode/test/e2e/enterprise-server-sent-models.test.ts @@ -1,5 +1,9 @@ import { expect } from '@playwright/test' -import type { ServerModelConfiguration } from '@sourcegraph/cody-shared/src/models' +import type { + ModelCategory, + ModelTier, + ServerModelConfiguration, +} from '@sourcegraph/cody-shared/src/models' import { createEmptyChatPanel, sidebarSignin } from './common' import { type ExtraWorkspaceSettings, test } from './helpers' @@ -51,9 +55,9 @@ const SERVER_MODELS: ServerModelConfiguration = { displayName: 'Opus', modelName: 'anthropic.claude-3-opus-20240229-v1_0', capabilities: ['autocomplete', 'chat'], - category: 'balanced', + category: 'balanced' as ModelCategory, status: 'stable', - tier: 'enterprise', + tier: 'enterprise' as ModelTier, contextWindow: { maxInputTokens: 9000, maxOutputTokens: 4000, @@ -64,9 +68,9 @@ const SERVER_MODELS: ServerModelConfiguration = { displayName: 'Instant', modelName: 'anthropic.claude-instant-v1', capabilities: ['autocomplete', 'chat'], - category: 'balanced', + category: 'balanced' as ModelCategory, status: 'stable', - tier: 'enterprise', + tier: 'enterprise' as ModelTier, contextWindow: { maxInputTokens: 9000, maxOutputTokens: 4000, @@ -77,9 +81,9 @@ const SERVER_MODELS: ServerModelConfiguration = { displayName: 'Titan', modelName: 'amazon.titan-text-lite-v1', capabilities: ['autocomplete', 'chat'], - category: 'balanced', + category: 'balanced' as ModelCategory, status: 'stable', - tier: 'enterprise', + tier: 'enterprise' as ModelTier, contextWindow: { maxInputTokens: 9000, maxOutputTokens: 4000, diff --git a/vscode/test/fixtures/mock-server.ts b/vscode/test/fixtures/mock-server.ts index cd7eb8faa07..a6e816eb5aa 100644 --- a/vscode/test/fixtures/mock-server.ts +++ b/vscode/test/fixtures/mock-server.ts @@ -525,7 +525,7 @@ export class MockServer { res.sendStatus(200) }) - app.get('/.api/supported-llms', (req, res) => { + app.get('/.api/modelconfig/supported-models.json', (req, res) => { res.status(200).send(JSON.stringify(controller.availableLLMs)) }) From 0cbffb184fe5dd5c9a5f6e5c114236a06e441122 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Tue, 9 Jul 2024 19:44:19 -0700 Subject: [PATCH 25/34] updated recording --- .../recording.har.yaml | 1304 ++--------------- 1 file changed, 110 insertions(+), 1194 deletions(-) diff --git a/agent/recordings/defaultClient_631904893/recording.har.yaml b/agent/recordings/defaultClient_631904893/recording.har.yaml index f18c1f31dcc..f922db8ae68 100644 --- a/agent/recordings/defaultClient_631904893/recording.har.yaml +++ b/agent/recordings/defaultClient_631904893/recording.har.yaml @@ -5,7 +5,7 @@ log: name: Polly.JS version: 6.0.6 entries: - - _id: 2e7862e0c501fbdd157a5733d068fd52 + - _id: 8ffa79cf5668b64b3fd5ad5674e1d846 _order: 0 cache: {} request: @@ -15,7 +15,7 @@ log: - _fromType: array name: authorization value: token - REDACTED_0ba08837494d00e3943c46999589eb29a210ba8063f084fff511c8e4d1503909 + REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - _fromType: array name: content-type value: application/json; charset=utf-8 @@ -30,26 +30,28 @@ log: value: gzip,deflate - name: host value: sourcegraph.com - headersSize: 301 + headersSize: 289 httpVersion: HTTP/1.1 method: GET queryString: [] url: https://sourcegraph.com/.api/client-config response: - bodySize: 22 + bodySize: 188 content: + encoding: base64 mimeType: text/plain; charset=utf-8 - size: 22 - text: | - Invalid access token. + size: 188 + text: "[\"H4sIAAAAAAAAA2zMsQoCMRCE4T5PsVztE9hJsLjOznrPrBjI7koyQeW4d7dRBEn9z3xrI\ + CKaLp5eR+OlSJr2hNpl9wk3xjBwh0fXexHI+NkbXKOrsqU2NoCal47s9utXLu07aMoV\ + 0Q3yxDlb8sfQUU9S2uE0/ylhC28AAAD//wMAK/Ow9eAAAAA=\"]" cookies: [] headers: - name: date - value: Tue, 09 Jul 2024 02:18:43 GMT + value: Wed, 10 Jul 2024 02:43:59 GMT - name: content-type value: text/plain; charset=utf-8 - - name: content-length - value: "22" + - name: transfer-encoding + value: chunked - name: connection value: keep-alive - name: access-control-allow-credentials @@ -59,7 +61,8 @@ log: - name: cache-control value: no-cache, max-age=0 - name: vary - value: Cookie,Accept-Encoding,Authorization + value: Cookie,Accept-Encoding,Authorization,Cookie, Authorization, + X-Requested-With,Cookie - name: x-content-type-options value: nosniff - name: x-frame-options @@ -68,12 +71,14 @@ log: value: 1; mode=block - name: strict-transport-security value: max-age=31536000; includeSubDomains; preload - headersSize: 1263 + - name: content-encoding + value: gzip + headersSize: 1342 httpVersion: HTTP/1.1 redirectURL: "" - status: 401 - statusText: Unauthorized - startedDateTime: 2024-07-09T02:18:42.792Z + status: 200 + statusText: OK + startedDateTime: 2024-07-10T02:43:59.728Z time: 0 timings: blocked: -1 @@ -677,8 +682,7 @@ log: - speaker: human text: My name is Lars Monsen. - speaker: assistant - text: - Hello Lars Monsen, it's nice to meet you. I'm Cody, an AI coding assistant + text: Hello Lars Monsen, it's nice to meet you. I'm Cody, an AI coding assistant created by Sourcegraph. How can I help you with coding or development tasks today? - speaker: human @@ -892,8 +896,7 @@ log: - speaker: human text: What model are you? - speaker: assistant - text: - I am an AI assistant called Cody, created by Sourcegraph. I don't have + text: I am an AI assistant called Cody, created by Sourcegraph. I don't have information about my specific underlying model architecture or training. How can I assist you with coding or development tasks today? @@ -1243,929 +1246,65 @@ log: - speaker: human text: |- Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

                          Messages

                          -
                            - {messages.map((message) => ( -
                          • {message.text}
                          • ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: >- - You have access to the provided codebase context. Answer - positively without apologizing. - - - Question: What is Squirrel? - model: anthropic/claude-3-5-sonnet-20240620 - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: api-version - value: "1" - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 - response: - bodySize: 12671 - content: - mimeType: text/event-stream - size: 12671 - text: >+ - event: completion - - data: {"completion":"According to the codebase context, Squirrel is an interface defined in the file src/squirrel.ts. Despite its name, it's not actually related to squirrels. The interface is described as mocking something completely unrelated to squirrels and is associated with the implementation of precise code navigation in Sourcegraph. The interface is currently empty in the provided code snippet, suggesting it might be a placeholder or used for type checking purposes in the larger codebase.","stopReason":"end_turn"} - - - event: done - - data: {} - - cookies: [] - headers: - - name: date - value: Tue, 09 Jul 2024 17:21:59 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: 1299 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-09T17:21:57.420Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 3dfe2b82e069e3bc00bdcb4a39f551b0 - _order: 0 - cache: {} - request: - bodySize: 2396 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-e9b28056068176deb36ec8b8b7255605-7d68974ce4e3254a-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 415 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: >- - Codebase context from file src/squirrel.ts: - - ```typescript - - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} - - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

                            Messages

                            -
                              - {messages.map((message) => ( -
                            • {message.text}
                            • ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: >- - My selected code from codebase file - src/multiple-selections.ts:7-8: - - ``` - - - function anotherFunction() {} - - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: >- - You have access to the provided codebase context. Answer - positively without apologizing. - - - Question: What is the name of the function that I have selected? Only answer with the name of the function, nothing else - model: anthropic/claude-3-5-sonnet-20240620 - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: api-version - value: "1" - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 - response: - bodySize: 238 - content: - mimeType: text/event-stream - size: 238 - text: |+ - event: completion - data: {"completion":"anotherFunction","stopReason":"end_turn"} - - event: done - data: {} - - cookies: [] - headers: - - name: date - value: Tue, 09 Jul 2024 17:22:02 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: 1299 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-09T17:22:00.837Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 2929f1e3d05c90e1f35a897b2a65bf99 - _order: 0 - cache: {} - request: - bodySize: 2401 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-66a69f6343d73ef6e6ae7987fedeb0b7-1a71ba3f4d6f94b0-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 415 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: >- - Codebase context from file src/squirrel.ts: - - ```typescript - - /** - * Squirrel is an interface that mocks something completely unrelated to squirrels. - * It is related to the implementation of precise code navigation in Sourcegraph. - */ - export interface Squirrel {} - - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/multiple-selections.ts: - ```typescript - function outer() { - /* SELECTION_START */ - return function inner() {} - /* SELECTION_END */ - } - - /* SELECTION_2_START */ - function anotherFunction() {} - /* SELECTION_2_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/Heading.tsx: - ```typescript - import React = require("react"); - - interface HeadingProps { - text: string; - level?: number; - } - - /* CURSOR */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/ChatColumn.tsx: - ```typescript - import { useEffect } from "react"; - import React = require("react"); - - /* SELECTION_START */ export default function ChatColumn({ - messages, - setChatID, - isLoading, - }) { - /* SELECTION_END */ - useEffect(() => { - if (!isLoading) { - setChatID(messages[0].chatID); - } - }, [messages]); - return ( - <> -

                              Messages

                              -
                                - {messages.map((message) => ( -
                              • {message.text}
                              • ``` - - speaker: assistant - text: Ok. - - speaker: human - text: |- - Codebase context from file src/animal.ts: - ```typescript - /* SELECTION_START */ - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - /* SELECTION_END */ - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: >- - My selected code from codebase file - src/multiple-selections.ts:2-4: - - ``` - - return function inner() {} - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: >- - You have access to the provided codebase context. Answer - positively without apologizing. - - - Question: What is the name of the function that I have selected? Only answer with the name of the function, nothing else - model: anthropic/claude-3-5-sonnet-20240620 - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: api-version - value: "1" - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 - response: - bodySize: 158 - content: - mimeType: text/event-stream - size: 158 - text: |+ - event: completion - data: {"completion":"inner","stopReason":"end_turn"} - - event: done - data: {} - - cookies: [] - headers: - - name: date - value: Tue, 09 Jul 2024 17:22: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: 1299 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-09T17:22:02.717Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: eafc84e2e421e4cc3e3f5af82b377d1a - _order: 0 - cache: {} - request: - bodySize: 1612 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-1eee3496dd9898117db3037dc788a4cf-4ff9992c883e6585-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 415 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: > - Codebase context from file path src/animal.ts: /* - SELECTION_START */ - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - - /* SELECTION_END */ - - speaker: assistant - text: Ok. - - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: - "Explain what @src/animal.ts:1-6 ( @src/animal.ts ) does in simple terms. - Assume the audience is a beginner programmer who has just - learned the language features and basic syntax. Focus on - explaining: 1) The purpose of the code 2) What input(s) it - takes 3) What output(s) it produces 4) How it achieves its - purpose through the logic and algorithm. 5) Any important - logic flows or data transformations happening. Use simple - language a beginner could understand. Include enough detail to - give a full picture of what the code aims to accomplish - without getting too technical. Format the explanation in - coherent paragraphs, using proper punctuation and grammar. - Write the explanation assuming no prior context about the code - is known. Do not make assumptions about variables or functions - not shown in the shared code. Start the answer with the name - of the code that is being explained." - model: anthropic/claude-3-5-sonnet-20240620 - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: api-version - value: "1" - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 - response: - bodySize: 143912 - content: - mimeType: text/event-stream - size: 143912 - text: >+ - event: completion - - data: {"completion":"The Animal Interface\n\nThis code defines an interface named \"Animal\" in TypeScript. An interface is like a blueprint or a contract that describes the structure of an object. In this case, it's describing what properties and methods an animal should have.\n\nThe purpose of this code is to establish a common structure for different types of animals in a program. It doesn't create any animals itself, but rather sets up a template that other parts of the code can use to ensure consistency when working with animal objects.\n\nThis interface doesn't take any inputs or produce any outputs directly. Instead, it defines what an animal object should look like in terms of its properties and methods.\n\nThe Animal interface specifies three things that any object representing an animal should have:\n\n1. A \"name\" property, which is a string (text) representing the animal's name.\n2. A \"makeAnimalSound\" method, which is a function that returns a string. This method is likely intended to represent the sound the animal makes (like \"moo\" for a cow or \"meow\" for a cat).\n3. An \"isMammal\" property, which is a boolean (true or false) indicating whether the animal is a mammal or not.\n\nBy defining this interface, the code ensures that any object in the program that claims to be an \"Animal\" must have these three properties. This helps maintain consistency and prevents errors that might occur if some animal objects were missing expected properties or methods.\n\nIn a larger program, other parts of the code could use this interface to create specific types of animals (like dogs, cats, or birds) that all follow this common structure. This makes it easier to work with different animals in a consistent way throughout the program.","stopReason":"end_turn"} - - - event: done - - data: {} - - cookies: [] - headers: - - name: date - value: Tue, 09 Jul 2024 17:22:05 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: 1299 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-09T17:22:04.369Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 822d77b2fec7689ba96d02aee9ebe965 - _order: 0 - cache: {} - request: - bodySize: 2488 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-cc5c4ede894e0a596063d44a51e2d571-264690023a30700f-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 415 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: > - Codebase context from file path src/example.test.ts: import { - expect } from 'vitest' - - import { it } from 'vitest' - - import { describe } from 'vitest' - - - describe('test block', () => { - it('does 1', () => { - expect(true).toBe(true) - }) - - it('does 2', () => { - expect(true).toBe(true) - }) - - it('does something else', () => { - // This line will error due to incorrect usage of `performance.now` - const startTime = performance.now(/* CURSOR */) - }) - }) - - speaker: assistant - text: Ok. - - speaker: human - text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean - } - ``` - - speaker: assistant - text: Ok. - - speaker: human - text: - Review the shared code context and configurations to identify the test - framework and libraries in use. Then, generate a suite of - multiple unit tests for the functions in using the - detected test framework and libraries. Be sure to import the - function being tested. Follow the same patterns as any shared - context. Only add packages, imports, dependencies, and - assertions if they are used in the shared code. Pay attention - to the file path of each shared context to see if test for - already exists. If one exists, focus on generating - new unit tests for uncovered cases. If none are detected, - import common unit test libraries for {languageName}. Focus on - validating key functionality with simple and complete - assertions. Only include mocks if one is detected in the - shared code. Before writing the tests, identify which test - libraries and frameworks to import, e.g. 'No new imports - needed - using existing libs' or 'Importing test framework - that matches shared context usage' or 'Importing the defined - framework', etc. Then briefly summarize test coverage and any - limitations. At the end, enclose the full completed code for - the new unit tests, including all necessary imports, in a - single markdown codeblock. No fragments or TODO. The new tests - should validate expected functionality and cover edge cases - for with all required imports, including importing - the function being tested. Do not repeat existing tests. - model: anthropic/claude-3-5-sonnet-20240620 - temperature: 0 - topK: -1 - topP: -1 - queryString: - - name: api-version - value: "1" - - name: client-name - value: defaultclient - - name: client-version - value: v1 - url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 - response: - bodySize: 459556 - content: - mimeType: text/event-stream - size: 459556 - text: >+ - event: completion - - data: {"completion":"Based on the shared context, I can see that the project is using Vitest as the test framework. The imports for `expect`, `it`, and `describe` from Vitest are already present in the example test file. We'll use the same pattern for our new tests.\n\nFor the Animal interface, we can't directly test it since it's an interface, but we can create tests for a class that implements this interface to ensure it adheres to the contract.\n\nSummary:\n- No new imports needed - using existing libs (Vitest)\n- We'll create a mock implementation of the Animal interface for testing\n- Tests will cover the implementation of all properties and methods defined in the interface\n- Edge cases will include testing with different animal types\n\nHere's the full completed code for the new unit tests:\n\n```typescript\nimport { expect, it, describe } from 'vitest'\nimport { Animal } from '../src/animal'\n\n// Mock implementation of Animal interface for testing\nclass TestAnimal implements Animal {\n name: string\n isMammal: boolean\n\n constructor(name: string, isMammal: boolean) {\n this.name = name\n this.isMammal = isMammal\n }\n\n makeAnimalSound(): string {\n return this.isMammal ? 'Meow' : 'Hiss'\n }\n}\n\ndescribe('Animal Interface Implementation', () =\u003e {\n it('should create an animal with a name', () =\u003e {\n const cat = new TestAnimal('Whiskers', true)\n expect(cat.name).toBe('Whiskers')\n })\n\n it('should correctly identify if an animal is a mammal', () =\u003e {\n const cat = new TestAnimal('Whiskers', true)\n const snake = new TestAnimal('Slither', false)\n expect(cat.isMammal).toBe(true)\n expect(snake.isMammal).toBe(false)\n })\n\n it('should return a sound when makeAnimalSound is called', () =\u003e {\n const cat = new TestAnimal('Whiskers', true)\n const snake = new TestAnimal('Slither', false)\n expect(cat.makeAnimalSound()).toBe('Meow')\n expect(snake.makeAnimalSound()).toBe('Hiss')\n })\n\n it('should allow changing the name of the animal', () =\u003e {\n const animal = new TestAnimal('Original', true)\n expect(animal.name).toBe('Original')\n animal.name = 'New Name'\n expect(animal.name).toBe('New Name')\n })\n\n it('should not allow changing the isMammal property after initialization', () =\u003e {\n const animal = new TestAnimal('Test', true)\n expect(() =\u003e {\n (animal as any).isMammal = false\n }).toThrow()\n })\n})\n```\n\nThis test suite covers the main aspects of the Animal interface:\n1. Creating an animal with a name\n2. Correctly identifying if an animal is a mammal\n3. Making an animal sound\n4. Changing the name of an animal\n5. Ensuring that the isMammal property cannot be changed after initialization (TypeScript's readonly behavior)\n\nThese tests should provide good coverage for any class implementing the Animal interface. Note that the actual implementation might vary, so you may need to adjust the expected sounds or behaviors based on your specific implementation.","stopReason":"end_turn"} - - - event: done - - data: {} - - cookies: [] - headers: - - name: date - value: Tue, 09 Jul 2024 17:22:12 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: 1299 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-09T17:22:10.933Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: b5007a5a22b701f645e334fca0392450 - _order: 0 - cache: {} - request: - bodySize: 1408 - cookies: [] - headers: - - name: content-type - value: application/json - - name: accept-encoding - value: gzip;q=0 - - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - name: user-agent - value: defaultClient / v1 - - name: traceparent - value: 00-fd62fd6930b0468de03c405b02672ba5-c96cbedac6d67b1e-01 - - name: connection - value: keep-alive - - name: host - value: sourcegraph.com - headersSize: 415 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json - params: [] - textJSON: - maxTokensToSample: 4000 - messages: - - speaker: system - text: You are Cody, an AI coding assistant from Sourcegraph. - - speaker: human - text: > - Codebase context from file path src/animal.ts: /* - SELECTION_START */ - - export interface Animal { - name: string - makeAnimalSound(): string - isMammal: boolean + ```typescript + import React = require("react"); + + interface HeadingProps { + text: string; + level?: number; } - /* SELECTION_END */ + /* CURSOR */ + ``` - speaker: assistant text: Ok. - speaker: human text: |- - My selected code from codebase file src/animal.ts:1-6: - ``` + Codebase context from file src/ChatColumn.tsx: + ```typescript + import { useEffect } from "react"; + import React = require("react"); + /* SELECTION_START */ export default function ChatColumn({ + messages, + setChatID, + isLoading, + }) { + /* SELECTION_END */ + useEffect(() => { + if (!isLoading) { + setChatID(messages[0].chatID); + } + }, [messages]); + return ( + <> +

                                Messages

                                +
                                  + {messages.map((message) => ( +
                                • {message.text}
                                • ``` + - speaker: assistant + text: Ok. + - speaker: human + text: |- + Codebase context from file src/animal.ts: + ```typescript + /* SELECTION_START */ export interface Animal { name: string makeAnimalSound(): string isMammal: boolean } + /* SELECTION_END */ ``` - speaker: assistant text: Ok. - speaker: human - text: - Please review and analyze @src/animal.ts:1-6 ( @src/animal.ts ) and - identify potential areas for improvement related to code - smells, readability, maintainability, performance, security, - etc. Do not list issues already addressed in the given code. - Focus on providing up to 5 constructive suggestions that could - make the code more robust, efficient, or align with best - practices. For each suggestion, provide a brief explanation of - the potential benefits. After listing any recommendations, - summarize if you found notable opportunities to enhance the - code quality overall or if the code generally follows sound - design principles. If no issues found, reply 'There are no - errors.' + text: >- + You have access to the provided codebase context. Answer + positively without apologizing. + + + Question: What is Squirrel? model: anthropic/claude-3-5-sonnet-20240620 temperature: 0 topK: -1 @@ -2179,14 +1318,14 @@ log: value: v1 url: https://sourcegraph.com/.api/completions/stream?api-version=1&client-name=defaultclient&client-version=v1 response: - bodySize: 117745 + bodySize: 12671 content: mimeType: text/event-stream - size: 117745 + size: 12671 text: >+ event: completion - data: {"completion":"After reviewing the code snippet from @src/animal.ts:1-6, I don't find any significant issues or areas for improvement. The code generally follows sound design principles for defining a TypeScript interface. Here's a brief analysis:\n\n1. The interface is clearly named and exported, making it accessible for use in other parts of the codebase.\n2. It defines three properties with appropriate types, which is good for type safety.\n3. The method signature `makeAnimalSound(): string` is well-defined, indicating it returns a string.\n\nOverall, this interface provides a solid foundation for representing an Animal in the system. It's concise, readable, and follows TypeScript best practices for interface definition.\n\nWhile there are no pressing issues to address, here are a couple of minor suggestions that might be considered, depending on the broader context of the application:\n\n1. Consider adding JSDoc comments to provide more detailed documentation for the interface and its members. This can improve code maintainability and make it easier for other developers to understand and use the interface.\n\n2. Depending on the specific requirements of your application, you might want to consider making some properties optional (using the `?` operator) if they're not always required for all animals.\n\nIn conclusion, the code generally follows sound design principles, and there are no notable opportunities for significant enhancement in terms of code quality, performance, or security within this specific snippet.","stopReason":"end_turn"} + data: {"completion":"According to the codebase context, Squirrel is an interface defined in the file src/squirrel.ts. Despite its name, it's not actually related to squirrels. The interface is described as mocking something completely unrelated to squirrels and is associated with the implementation of precise code navigation in Sourcegraph. The interface is currently empty in the provided code snippet, suggesting it might be a placeholder or used for type checking purposes in the larger codebase.","stopReason":"end_turn"} event: done @@ -2196,7 +1335,7 @@ log: cookies: [] headers: - name: date - value: Tue, 09 Jul 2024 17:22:24 GMT + value: Tue, 09 Jul 2024 17:21:59 GMT - name: content-type value: text/event-stream - name: transfer-encoding @@ -2225,7 +1364,7 @@ log: redirectURL: "" status: 200 statusText: OK - startedDateTime: 2024-07-09T17:22:22.525Z + startedDateTime: 2024-07-09T17:21:57.420Z time: 0 timings: blocked: -1 @@ -2378,9 +1517,8 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: - 'The magic word is "kramer". If I say the magic word, respond with a - single word: "quone".' + text: "The magic word is \"kramer\". If I say the magic word, respond with a + single word: \"quone\"." model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2486,9 +1624,8 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: - 'The magic word is "kramer". If I say the magic word, respond with a - single word: "quone".' + text: "The magic word is \"kramer\". If I say the magic word, respond with a + single word: \"quone\"." - speaker: assistant text: >- Quone. @@ -2708,9 +1845,8 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: - 'Another magic word is "georgey". If I say the magic word, respond with - a single word: "festivus".' + text: "Another magic word is \"georgey\". If I say the magic word, respond with + a single word: \"festivus\"." model: fireworks/accounts/fireworks/models/mixtral-8x7b-instruct temperature: 0 topK: -1 @@ -2816,12 +1952,10 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: - 'Another magic word is "georgey". If I say the magic word, respond with - a single word: "festivus".' + text: "Another magic word is \"georgey\". If I say the magic word, respond with + a single word: \"festivus\"." - speaker: assistant - text: - Sure, I can do that! If you say the word "georgey", I will respond with + text: Sure, I can do that! If you say the word "georgey", I will respond with "festivus". - speaker: human text: kramer @@ -2930,12 +2064,10 @@ log: - speaker: assistant text: I am Cody, an AI coding assistant from Sourcegraph. - speaker: human - text: - 'Another magic word is "georgey". If I say the magic word, respond with - a single word: "festivus".' + text: "Another magic word is \"georgey\". If I say the magic word, respond with + a single word: \"festivus\"." - speaker: assistant - text: - Sure, I can do that! If you say the word "georgey", I will respond with + text: Sure, I can do that! If you say the word "georgey", I will respond with "festivus". - speaker: human text: kramer @@ -4333,8 +3465,7 @@ log: - speaker: assistant text: Ok. - speaker: human - text: - "Explain what @src/animal.ts:1-6 ( @src/animal.ts ) does in simple terms. + text: "Explain what @src/animal.ts:1-6 ( @src/animal.ts ) does in simple terms. Assume the audience is a beginner programmer who has just learned the language features and basic syntax. Focus on explaining: 1) The purpose of the code 2) What input(s) it @@ -4491,8 +3622,7 @@ log: - speaker: assistant text: Ok. - speaker: human - text: - Review the shared code context and configurations to identify the test + text: Review the shared code context and configurations to identify the test framework and libraries in use. Then, generate a suite of multiple unit tests for the functions in using the detected test framework and libraries. Be sure to import the @@ -4646,8 +3776,7 @@ log: - speaker: assistant text: Ok. - speaker: human - text: - Please review and analyze @src/animal.ts:1-6 ( @src/animal.ts ) and + text: Please review and analyze @src/animal.ts:1-6 ( @src/animal.ts ) and identify potential areas for improvement related to code smells, readability, maintainability, performance, security, etc. Do not list issues already addressed in the given code. @@ -4726,212 +3855,6 @@ log: send: 0 ssl: -1 wait: 0 - - _id: 4d7b84f278a68f81a65e407b527c4a0e - _order: 0 - cache: {} - request: - bodySize: 217 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_4a92106dd3be39a589d6e2d0a6e32b705744d4007d74518fdfd1dbf953176dc6 - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: defaultClient / v1 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "217" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 332 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query CodyConfigFeaturesResponse { - site { - codyConfigFeatures { - chat - autoComplete - commands - attribution - } - } - } - variables: {} - queryString: - - name: CodyConfigFeaturesResponse - value: null - url: https://sourcegraph.com/.api/graphql?CodyConfigFeaturesResponse - response: - bodySize: 22 - content: - mimeType: text/plain; charset=utf-8 - size: 22 - text: | - Invalid access token. - cookies: [] - headers: - - name: date - value: Wed, 03 Jul 2024 06:24:14 GMT - - name: content-type - value: text/plain; charset=utf-8 - - name: content-length - value: "22" - - name: connection - value: keep-alive - - name: access-control-allow-credentials - value: "true" - - name: access-control-allow-origin - value: "" - - name: cache-control - value: no-cache, max-age=0 - - name: vary - value: Cookie,Accept-Encoding,Authorization - - 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: 1263 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 401 - statusText: Unauthorized - startedDateTime: 2024-07-03T06:24:13.717Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - - _id: 12581f1c735a04aeb88af7a54cd007b2 - _order: 0 - cache: {} - request: - bodySize: 217 - cookies: [] - headers: - - _fromType: array - name: authorization - value: token - REDACTED_d5e0f0a37c9821e856b923fe14e67a605e3f6c0a517d5a4f46a4e35943ee0f6d - - _fromType: array - name: content-type - value: application/json; charset=utf-8 - - _fromType: array - name: user-agent - value: defaultClient / v1 - - _fromType: array - name: accept - value: "*/*" - - _fromType: array - name: content-length - value: "217" - - _fromType: array - name: accept-encoding - value: gzip,deflate - - name: host - value: sourcegraph.com - headersSize: 332 - httpVersion: HTTP/1.1 - method: POST - postData: - mimeType: application/json; charset=utf-8 - params: [] - textJSON: - query: |- - - query CodyConfigFeaturesResponse { - site { - codyConfigFeatures { - chat - autoComplete - commands - attribution - } - } - } - variables: {} - queryString: - - name: CodyConfigFeaturesResponse - value: null - url: https://sourcegraph.com/.api/graphql?CodyConfigFeaturesResponse - response: - bodySize: 162 - content: - encoding: base64 - mimeType: application/json - size: 162 - text: - "[\"H4sIAAAAAAAAAzyLwQqA\",\"IBAF/2XPfYFXof/YdC0h3dDnIcR/Dws6DQwznTyDyXSq\ - ETLp1N9Wc4j7KoxWpL72YJBBabIQN6jVdJ0yj885TYmzr38DlLg1RM1kAp9VxhjjAQA\ - A//8=\",\"AwCHzi5CbgAAAA==\"]" - cookies: [] - headers: - - name: date - value: Wed, 03 Jul 2024 06:24:15 GMT - - name: content-type - value: application/json - - 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, max-age=0 - - 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 - - name: content-encoding - value: gzip - headersSize: 1333 - httpVersion: HTTP/1.1 - redirectURL: "" - status: 200 - statusText: OK - startedDateTime: 2024-07-03T06:24:14.717Z - time: 0 - timings: - blocked: -1 - connect: -1 - dns: -1 - receive: 0 - send: 0 - ssl: -1 - wait: 0 - _id: 9d0e130a38eaf9d3cd8d9512afc14b87 _order: 0 cache: {} @@ -4968,7 +3891,7 @@ log: params: [] textJSON: query: |- - + query ContextFilters { site { codyContextFilters(version: V1) { @@ -4987,8 +3910,7 @@ log: encoding: base64 mimeType: application/json size: 114 - text: - "[\"H4sIAAAAAAAAA6pWSkks\",\"SVSyqlYqzixJBdHJ+SmVzvl5JakVJW6ZOSWpRcUg0aLE\ + text: "[\"H4sIAAAAAAAAA6pWSkks\",\"SVSyqlYqzixJBdHJ+SmVzvl5JakVJW6ZOSWpRcUg0aLE\ ciWrvNKcnNra2loAAAAA//8=\",\"AwA2LshlNQAAAA==\"]" cookies: [] headers: @@ -5070,7 +3992,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -5174,7 +4096,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -5273,7 +4195,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -5375,7 +4297,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -5472,7 +4394,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -5496,8 +4418,7 @@ log: encoding: base64 mimeType: application/json size: 251 - text: - "[\"H4sIAAAAAAAAA3zOwQqC\",\"QBAG4HeZs+K0BqFXr3rrBYbdMRdtJ3ZXKmTfPSyiSOg0\ + text: "[\"H4sIAAAAAAAAA3zOwQqC\",\"QBAG4HeZs+K0BqFXr3rrBYbdMRdtJ3ZXKmTfPSyiSOg0\ 8PP/H7OAoUhQLxBs5PVqMfe27RpxvT3NnqIV98wHip0YnqAGcnHwcrG60BPNhvMyD+I\ cx1yh2qNSFWSfQUe3o4zsAtQ7hYgZ9BRi898byI7ziyvxAD+bLanlfJl4ffaN9tbzVf\ wYihDJazHsYdP7gipETCmlBwAAAP//AwBQeP+1EwEAAA==\"]" @@ -5581,7 +4502,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmConfiguration { site { codyLLMConfiguration { @@ -5600,8 +4521,7 @@ log: encoding: base64 mimeType: application/json size: 132 - text: - "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdHJ+SmVPj6+zvl5aZnppUWJJZn5eWD53MSiE\ + text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdHJ+SmVPj6+zvl5aZnppUWJJZn5eWD53MSiE\ uf8vJLUipLwzLyU/HIlK6XUvMSknNQUpdra2loAAAAA//8DAOgINKVLAAAA\"]" textDecoded: data: @@ -5688,7 +4608,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -5787,7 +4707,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -5884,7 +4804,7 @@ log: params: [] textJSON: query: |- - + query CurrentSiteCodyLlmProvider { site { codyLLMConfiguration { @@ -5903,8 +4823,7 @@ log: encoding: base64 mimeType: application/json size: 128 - text: - "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdHJ+SmVPj6+zvl5aZnppUWJJZn5eSDxgqL8s\ + text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdHJ+SmVPj6+zvl5aZnppUWJJZn5eSDxgqL8s\ syU1CIlK6Xi/NKi5NT0osSCDKXa2tpaAAAAAP//AwAfFAXARQAAAA==\"]" textDecoded: data: @@ -5991,7 +4910,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -6101,7 +5020,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -6209,7 +5128,7 @@ log: params: [] textJSON: query: |- - + query CurrentUser { currentUser { id @@ -6239,8 +5158,7 @@ log: encoding: base64 mimeType: application/json size: 379 - text: - "[\"H4sIAAAAAAAAA2RPy04=\",\"wkAU/Ze7bmkNUdpJSBQEF2jjIzQY4+J2emmnj5k6DxSa\ + text: "[\"H4sIAAAAAAAAA2RPy04=\",\"wkAU/Ze7bmkNUdpJSBQEF2jjIzQY4+J2emmnj5k6DxSa\ /jtpMHHh7pycx72nhxwtAuuBO61J2q0hPVKRA4N0lzS8Uqfk/uXqqeJz8KBEk5IWe0H\ 5qkXRALPakQe5MF2DxwRbAgZvymlOhcauXCjrx2EYggfOkJYXg/kzZMrGtb+X360DD/\ CAFvX29REYlNZ2hgVBU04nhVJFQ2MDV9KStBOu2gCDu2URKb5Z41f2Tm5RZ9V1vl6df\ @@ -6326,7 +5244,7 @@ log: params: [] textJSON: query: |- - + query CurrentUserCodySubscription { currentUser { codySubscription { @@ -6349,8 +5267,7 @@ log: encoding: base64 mimeType: application/json size: 228 - text: - "[\"H4sIAAAAAAAAA1zMsQrCMBSF4Xc5c4U2FoVsRToIgqWtDm6xyRCoSbi5GUrJu4uCoI7n5\ + text: "[\"H4sIAAAAAAAAA1zMsQrCMBSF4Xc5c4U2FoVsRToIgqWtDm6xyRCoSbi5GUrJu4uCoI7n5\ +Os0IoV5IopERnHl2joPb1ehnSPE9nA1rtXi6w4RUg0h/F4bVEgzMpBouvPKKBCmJeO\ fK/YnOzDcoRkSqb4fHeGrNcDK+KGISFKUW/K3aaqRyFkVcmtuOFPt05/2f2vzTnnJwA\ AAP//AwBuKtnYwgAAAA==\"]" @@ -6443,7 +5360,7 @@ log: params: [] textJSON: query: |- - + query Repository($name: String!) { repository(name: $name) { id @@ -6539,7 +5456,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion @@ -6636,7 +5553,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion @@ -6731,7 +5648,7 @@ log: params: [] textJSON: query: |- - + query SiteProductVersion { site { productVersion @@ -6748,8 +5665,7 @@ log: encoding: base64 mimeType: application/json size: 136 - text: - "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdEFRfkppcklYalFxZn5eUpWSkYWBuYW5vFGB\ + text: "[\"H4sIAAAAAAAAA6pWSkksSVSyqlYqzixJBdEFRfkppcklYalFxZn5eUpWSkYWBuYW5vFGB\ kYmugbmugbG8aZ6JrqGRoaJBoZJqUlmpqlKtbW1AAAAAP//AwC1tndfSQAAAA==\"]" textDecoded: data: From fad14029bae31bb3f0bffb3208dd07376b6d4427 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Tue, 9 Jul 2024 19:57:53 -0700 Subject: [PATCH 26/34] switched e2e tests to use new server-sent models config --- .../e2e/enterprise-server-sent-models.test.ts | 63 +++++++++---------- vscode/test/fixtures/mock-server.ts | 2 + 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/vscode/test/e2e/enterprise-server-sent-models.test.ts b/vscode/test/e2e/enterprise-server-sent-models.test.ts index 82a1a395dda..ec3bf8c0054 100644 --- a/vscode/test/e2e/enterprise-server-sent-models.test.ts +++ b/vscode/test/e2e/enterprise-server-sent-models.test.ts @@ -5,45 +5,42 @@ import type { ServerModelConfiguration, } from '@sourcegraph/cody-shared/src/models' import { createEmptyChatPanel, sidebarSignin } from './common' -import { type ExtraWorkspaceSettings, test } from './helpers' +import { test } from './helpers' -test.extend({ - extraWorkspaceSettings: { - 'cody.dev.useServerDefinedModels': true, - }, -})( - 'allows multiple enterprise models when server-sent models is enabled', - async ({ page, server, sidebar }) => { - server.setAvailableLLMs(SERVER_MODELS) - await sidebarSignin(page, sidebar, true) - // Open chat. - const [chatFrame] = await createEmptyChatPanel(page) - let modelSelect = chatFrame.getByRole('combobox', { name: 'Select a model' }).last() +test('allows multiple enterprise models when server-sent models is enabled', async ({ + page, + server, + sidebar, +}) => { + server.setAvailableLLMs(SERVER_MODELS) + await sidebarSignin(page, sidebar, true) + // Open chat. + const [chatFrame] = await createEmptyChatPanel(page) + let modelSelect = chatFrame.getByRole('combobox', { name: 'Select a model' }).last() - // First model in the server list should be selected as default - await expect(modelSelect).toBeEnabled() - await expect(modelSelect).toHaveText(/^Opus/) + // First model in the server list should be selected as default + await expect(modelSelect).toBeEnabled() + await expect(modelSelect).toHaveText(/^Opus/) - // Change selection to Titan and assert it was updated - // Note: currently the backend doesn't respect frontend enterprise - // model selection so we don't test that it switches models here - await modelSelect.click() - const modelChoices = chatFrame.getByRole('listbox', { name: 'Suggestions' }) - await modelChoices.getByRole('option', { name: 'Titan' }).click() - await expect(modelSelect).toHaveText(/^Titan/) + // Change selection to Titan and assert it was updated + // Note: currently the backend doesn't respect frontend enterprise + // model selection so we don't test that it switches models here + await modelSelect.click() + const modelChoices = chatFrame.getByRole('listbox', { name: 'Suggestions' }) + await modelChoices.getByRole('option', { name: 'Titan' }).click() + await expect(modelSelect).toHaveText(/^Titan/) - // Close chat window and create a new one and assert the default model is preserved - const chatTab = page.getByRole('tab', { name: 'New Chat' }) - await chatTab.getByRole('button', { name: /^Close/ }).click() + // Close chat window and create a new one and assert the default model is preserved + const chatTab = page.getByRole('tab', { name: 'New Chat' }) + await chatTab.getByRole('button', { name: /^Close/ }).click() - const [newChatFrame] = await createEmptyChatPanel(page) - modelSelect = newChatFrame.getByRole('combobox', { name: 'Select a model' }).last() + const [newChatFrame] = await createEmptyChatPanel(page) + modelSelect = newChatFrame.getByRole('combobox', { name: 'Select a model' }).last() - // First model in the server list should be selected as default - await expect(modelSelect).toBeEnabled() - await expect(modelSelect).toHaveText(/^Titan/) - } -) + // First model in the server list should be selected as default + await expect(modelSelect).toBeEnabled() + await expect(modelSelect).toHaveText(/^Titan/) +}) const SERVER_MODELS: ServerModelConfiguration = { schemaVersion: '1.0', diff --git a/vscode/test/fixtures/mock-server.ts b/vscode/test/fixtures/mock-server.ts index a6e816eb5aa..324971f4d9f 100644 --- a/vscode/test/fixtures/mock-server.ts +++ b/vscode/test/fixtures/mock-server.ts @@ -358,6 +358,8 @@ export class MockServer { autoCompleteEnabled: true, customCommandsEnabled: true, attributionEnabled: attribution, + // When server-sent LLMs have been set, we enable the models api + modelsAPIEnabled: !!controller.availableLLMs, })) }) app.post('/.api/graphql', (req, res) => { From b8a38627d95bdae7a5f968f0aed1949aba7061ac Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Wed, 10 Jul 2024 11:01:29 -0700 Subject: [PATCH 27/34] Removed stub models and updated changelog --- lib/shared/src/sourcegraph-api/rest/client.ts | 16 ++++++++-------- vscode/CHANGELOG.md | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/shared/src/sourcegraph-api/rest/client.ts b/lib/shared/src/sourcegraph-api/rest/client.ts index 91416fde55f..027214083e2 100644 --- a/lib/shared/src/sourcegraph-api/rest/client.ts +++ b/lib/shared/src/sourcegraph-api/rest/client.ts @@ -1,9 +1,4 @@ -import { - Model, - type ModelCategory, - type ModelTier, - type ServerModelConfiguration, -} from '../../models/index' +import { Model, type ServerModelConfiguration } from '../../models/index' import { fetch } from '../../fetch' import { addTraceparent, wrapInActiveSpan } from '../../tracing' @@ -67,12 +62,13 @@ export class RestClient { // // NOTE: This API endpoint hasn't shippeted yet, and probably won't work for you. // Also, the URL definitely will change. - let serverSideConfig = await this.getRequest( + const serverSideConfig = await this.getRequest( 'getAvailableModels', '/.api/modelconfig/supported-models.json' ) if (serverSideConfig instanceof Error) { - serverSideConfig = testModels + return [] + // serverSideConfig = testModels } // TODO(PRIME-323): Do a proper review of the data model we will use to describe @@ -83,6 +79,9 @@ export class RestClient { } } +// TODO(jsm): delete these +// these are used for testing the server sent models and should be removed once the real API is available +/* const testModels: ServerModelConfiguration = { schemaVersion: '1.0', revision: '-', @@ -139,3 +138,4 @@ const testModels: ServerModelConfiguration = { codeCompletion: 'anthropic::unknown::anthropic.claude-instant-v1', }, } +*/ diff --git a/vscode/CHANGELOG.md b/vscode/CHANGELOG.md index e834aa94493..86c4bd12a64 100644 --- a/vscode/CHANGELOG.md +++ b/vscode/CHANGELOG.md @@ -9,7 +9,7 @@ This is a log of all notable changes to Cody for VS Code. [Unreleased] changes a - Ollama: Added support for running Cody offline with local Ollama models. [pull/4691](https://github.com/sourcegraph/cody/pull/4691) - Edit: Added support for users' to edit the applied edit before the diff view is removed. [pull/4684](https://github.com/sourcegraph/cody/pull/4684) - Autocomplete: Added experimental support for Gemini 1.5 Flash as the autocomplete model. To enable this experimental feature, update the `autocomplete.advanced.provider` configuration setting to `unstable-gemini`. Prerequisite: Your Sourcegraph instance (v5.5.0+) must first be configured to use Gemini 1.5 Flash as the autocomplete model. [pull/4743](https://github.com/sourcegraph/cody/pull/4743) -- Enterprise: Enabled support for multiple dynaic models if the Sourcegraph backend provides them. Requires the experimental flag `cody.dev.useServerDefinedModels` which currently returns a static list of models. Note: this won't work until the server side of this feature is merged. +- Enterprise: Enabled support for multiple dynaic models if the Sourcegraph backend provides them. Requires the experimental flag `modelsAPIEnabled` to be sent by the client config API. Note: this won't work until the server side of this feature is merged. [pull/4780](https://github.com/sourcegraph/cody/pull/4780) - Autocomplete: Fixed hot-streak cache keys for long documents. [pull/4817](https://github.com/sourcegraph/cody/pull/4817) - Autocomplete: Added an extra abort call to ensure request cancellation. [pull/4818](https://github.com/sourcegraph/cody/pull/4818) From f5b3fb461aca0474d00beb7b4c950b7e17943315 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Wed, 10 Jul 2024 15:58:56 -0700 Subject: [PATCH 28/34] review comments --- lib/shared/src/models/index.ts | 16 ++++++++++------ vscode/CHANGELOG.md | 2 +- vscode/src/chat/chat-view/SimpleChatModel.ts | 2 +- .../chat/chat-view/SimpleChatPanelProvider.ts | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index 4f737a1c467..dc2915de1e4 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -278,6 +278,7 @@ export class ModelsService { } private static getDefaultModel(type: ModelUsage, authStatus: AuthStatus): Model | undefined { + // Free users can only use the default free model, so we just find the first model they can use const models = ModelsService.getModelsByType(type) const firstModelUserCanUse = models.find(m => ModelsService.canUserUseModel(authStatus, m)) if (!authStatus.authenticated || isFreeUser(authStatus)) { @@ -288,13 +289,11 @@ export class ModelsService { return current } - // Check for the last selected model + // If this editor has local storage enabled, check to see if the + // user set a default model in a previous session. const lastSelectedModelID = ModelsService.storage?.get(ModelsService.storageKeys[type]) // return either the last selected model or first model they can use if any - return ( - models.find(m => m.model === lastSelectedModelID) || - models.find(m => ModelsService.canUserUseModel(authStatus, m)) - ) + return models.find(m => m.model === lastSelectedModelID) || firstModelUserCanUse } public static getDefaultEditModel(authStatus: AuthStatus): EditModel | undefined { @@ -324,9 +323,14 @@ export class ModelsService { return false } const tier = Model.tier(resolved) + // Cody Enterprise users are able to use any models that the backend says is supported. if (isEnterpriseUser(status)) { - return tier === 'enterprise' + return true } + + // A Cody Pro user can use any Free or Pro model, but not Enterprise. + // (But in reality, Sourcegraph.com wouldn't serve any Enterprise-only models to + // Cody Pro users anyways.) if (isCodyProUser(status)) { return tier !== 'enterprise' } diff --git a/vscode/CHANGELOG.md b/vscode/CHANGELOG.md index 86c4bd12a64..ab222e20941 100644 --- a/vscode/CHANGELOG.md +++ b/vscode/CHANGELOG.md @@ -9,7 +9,7 @@ This is a log of all notable changes to Cody for VS Code. [Unreleased] changes a - Ollama: Added support for running Cody offline with local Ollama models. [pull/4691](https://github.com/sourcegraph/cody/pull/4691) - Edit: Added support for users' to edit the applied edit before the diff view is removed. [pull/4684](https://github.com/sourcegraph/cody/pull/4684) - Autocomplete: Added experimental support for Gemini 1.5 Flash as the autocomplete model. To enable this experimental feature, update the `autocomplete.advanced.provider` configuration setting to `unstable-gemini`. Prerequisite: Your Sourcegraph instance (v5.5.0+) must first be configured to use Gemini 1.5 Flash as the autocomplete model. [pull/4743](https://github.com/sourcegraph/cody/pull/4743) -- Enterprise: Enabled support for multiple dynaic models if the Sourcegraph backend provides them. Requires the experimental flag `modelsAPIEnabled` to be sent by the client config API. Note: this won't work until the server side of this feature is merged. [pull/4780](https://github.com/sourcegraph/cody/pull/4780) +- Enterprise: Enabled support for multiple dynaic models if the Sourcegraph backend provides them. Requires the experimental flag `modelsAPIEnabled` to be sent by the client config API. [pull/4780](https://github.com/sourcegraph/cody/pull/4780) - Autocomplete: Fixed hot-streak cache keys for long documents. [pull/4817](https://github.com/sourcegraph/cody/pull/4817) - Autocomplete: Added an extra abort call to ensure request cancellation. [pull/4818](https://github.com/sourcegraph/cody/pull/4818) diff --git a/vscode/src/chat/chat-view/SimpleChatModel.ts b/vscode/src/chat/chat-view/SimpleChatModel.ts index e183f5d2e8f..c75624ce62a 100644 --- a/vscode/src/chat/chat-view/SimpleChatModel.ts +++ b/vscode/src/chat/chat-view/SimpleChatModel.ts @@ -30,7 +30,7 @@ export class SimpleChatModel { this.contextWindow = ModelsService.getContextWindowByID(this.modelID) } - public async updateModel(newModelID: string): Promise { + public async setDefaultModel(newModelID: string): Promise { this.modelID = newModelID this.contextWindow = ModelsService.getContextWindowByID(this.modelID) await ModelsService.setDefaultModel(ModelUsage.Chat, newModelID) diff --git a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts index a47848b452e..1857e1f29ae 100644 --- a/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts +++ b/vscode/src/chat/chat-view/SimpleChatPanelProvider.ts @@ -876,7 +876,7 @@ export class SimpleChatPanelProvider } private async handleSetChatModel(modelID: string): Promise { - this.chatModel.updateModel(modelID) + this.chatModel.setDefaultModel(modelID) } private async handleGetAllMentionProvidersMetadata(): Promise { From c71f3851354a7e7bf281bdd9e6a45ee773ed9225 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 11 Jul 2024 18:16:54 -0700 Subject: [PATCH 29/34] test(e2e): refactor command-core test to use focusSidebar helper function --- vscode/test/e2e/command-core.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode/test/e2e/command-core.test.ts b/vscode/test/e2e/command-core.test.ts index 9ee64532e34..357a8449f98 100644 --- a/vscode/test/e2e/command-core.test.ts +++ b/vscode/test/e2e/command-core.test.ts @@ -1,7 +1,7 @@ import { expect } from '@playwright/test' import * as mockServer from '../fixtures/mock-server' -import { sidebarExplorer, sidebarSignin } from './common' +import { focusSidebar, sidebarExplorer, sidebarSignin } from './common' import { type DotcomUrlOverride, type ExpectedV2Events, @@ -78,7 +78,7 @@ test.extend({ await page.getByText("fizzbuzz.push('Buzz')").click() // Bring the cody sidebar to the foreground - await page.getByRole('tab', { name: 'Cody', exact: true }).locator('a').click() + await focusSidebar(page) // Trigger the documentaton command await executeCommandInPalette(page, 'Document Code') From 98fbd94ddc12dfc1e161f9a8a546188e7c638f2e Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Thu, 11 Jul 2024 18:20:08 -0700 Subject: [PATCH 30/34] fixed type error --- agent/src/agent.ts | 2 +- vscode/src/chat/chat-view/ChatController.ts | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/agent/src/agent.ts b/agent/src/agent.ts index d95e59279a4..a4e682acb9b 100644 --- a/agent/src/agent.ts +++ b/agent/src/agent.ts @@ -1075,7 +1075,7 @@ export class Agent extends MessageHandler implements ExtensionClient { const authStatus = await vscode.commands.executeCommand('cody.auth.status') modelID ??= ModelsService.getDefaultChatModel(authStatus) ?? '' const chatMessages = messages?.map(PromptString.unsafe_deserializeChatMessage) ?? [] - const chatModel = new SimpleChatModel(modelID, chatID, chatMessages) + const chatModel = new ChatModel(modelID, chatID, chatMessages) await chatHistory.saveChat(authStatus, chatModel.toSerializedChatTranscript()) return this.createChatPanel( Promise.resolve({ diff --git a/vscode/src/chat/chat-view/ChatController.ts b/vscode/src/chat/chat-view/ChatController.ts index a4083f55b49..c3462f15f6d 100644 --- a/vscode/src/chat/chat-view/ChatController.ts +++ b/vscode/src/chat/chat-view/ChatController.ts @@ -535,12 +535,7 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv void this.sendConfig() // Get the latest model list available to the current user to update the ChatModel. - const authStatus = this.authProvider.getAuthStatus() - const models = ModelsService.getModels( - ModelUsage.Chat, - authStatus.isDotCom && !authStatus.userCanUpgrade - ) - this.handleSetChatModel(getDefaultModelID(this.authProvider, models)) + this.handleSetChatModel(getDefaultModelID(this.authProvider.getAuthStatus())) } // When the webview sends the 'ready' message, respond by posting the view config From bec077f546e13f01f9503ab23ad6d9a58e73cda7 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Fri, 12 Jul 2024 12:20:39 -0700 Subject: [PATCH 31/34] only set default model if the user took an action --- lib/shared/src/models/index.ts | 3 +++ vscode/src/chat/chat-view/ChatController.ts | 7 +++++-- vscode/src/chat/chat-view/ChatModel.ts | 4 +--- vscode/src/main.ts | 12 ++++++------ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/shared/src/models/index.ts b/lib/shared/src/models/index.ts index dc2915de1e4..0f938c80fab 100644 --- a/lib/shared/src/models/index.ts +++ b/lib/shared/src/models/index.ts @@ -1,5 +1,6 @@ import { type AuthStatus, isCodyProUser, isEnterpriseUser, isFreeUser } from '../auth/types' import { fetchLocalOllamaModels } from '../llm-providers/ollama/utils' +import { logDebug } from '../logger' import { CHAT_INPUT_TOKEN_BUDGET, CHAT_OUTPUT_TOKEN_BUDGET } from '../token/constants' import { ModelTag } from './tags' import { type ChatModel, type EditModel, type ModelContextWindow, ModelUsage } from './types' @@ -247,6 +248,7 @@ export class ModelsService { * NOTE: private instances can only support 1 provider ATM. */ public static setModels(models: Model[]): void { + logDebug('ModelsService', `Setting primary model: ${JSON.stringify(models.map(m => m.model))}`) ModelsService.primaryModels = models } @@ -312,6 +314,7 @@ export class ModelsService { if (!resolved.usage.includes(type)) { throw new Error(`Model "${resolved.model}" is not compatible with usage type "${type}".`) } + logDebug('ModelsService', `Setting default ${type} model to ${resolved.model}`) ModelsService.defaultModels.set(type, resolved) // If we have persistent storage set, write it there await ModelsService.storage?.set(ModelsService.storageKeys[type], resolved.model) diff --git a/vscode/src/chat/chat-view/ChatController.ts b/vscode/src/chat/chat-view/ChatController.ts index c3462f15f6d..abdc5118ecb 100644 --- a/vscode/src/chat/chat-view/ChatController.ts +++ b/vscode/src/chat/chat-view/ChatController.ts @@ -316,6 +316,9 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv break case 'chatModel': this.handleSetChatModel(message.model) + // Because this was a user action to change the model we will set that + // as a global default for chat + await ModelsService.setDefaultModel(ModelUsage.Chat, message.model) break case 'get-chat-models': this.postChatModels() @@ -876,8 +879,8 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv telemetryRecorder.recordEvent('cody.sidebar.abortButton', 'clicked') } - private async handleSetChatModel(modelID: string): Promise { - await this.chatModel.setDefaultModel(modelID) + private handleSetChatModel(modelID: string) { + this.chatModel.updateModel(modelID) this.postChatModels() } diff --git a/vscode/src/chat/chat-view/ChatModel.ts b/vscode/src/chat/chat-view/ChatModel.ts index 1051e43a1f9..7616483e2d9 100644 --- a/vscode/src/chat/chat-view/ChatModel.ts +++ b/vscode/src/chat/chat-view/ChatModel.ts @@ -5,7 +5,6 @@ import { type ContextItem, type Message, type ModelContextWindow, - ModelUsage, ModelsService, type SerializedChatInteraction, type SerializedChatTranscript, @@ -30,10 +29,9 @@ export class ChatModel { this.contextWindow = ModelsService.getContextWindowByID(this.modelID) } - public async setDefaultModel(newModelID: string): Promise { + public updateModel(newModelID: string) { this.modelID = newModelID this.contextWindow = ModelsService.getContextWindowByID(this.modelID) - await ModelsService.setDefaultModel(ModelUsage.Chat, newModelID) } public isEmpty(): boolean { diff --git a/vscode/src/main.ts b/vscode/src/main.ts index 3f009112e42..7cf5edea58e 100644 --- a/vscode/src/main.ts +++ b/vscode/src/main.ts @@ -263,7 +263,7 @@ const register = async ( ModelsService.setStorage(localStorage) // Functions that need to be called on auth status changes - async function handleAuthStatusChange(authStatus: AuthStatus) { + const handleAuthStatusChange = async (authStatus: AuthStatus) => { // NOTE: MUST update the config and graphQL client first. const newConfig = await getFullConfig() // Propagate access token through config @@ -310,10 +310,6 @@ const register = async ( // Add change listener to auth provider authProvider.addChangeListener(handleAuthStatusChange) - // Setup config watcher - configWatcher.onChange(setupAutocomplete, disposables) - await configWatcher.initAndOnChange(() => ModelsService.onConfigChange(), disposables) - setCommandController(platform.createCommandsProvider?.()) repoNameResolver.init(authProvider) @@ -563,7 +559,7 @@ const register = async ( dispose: disposeAutocomplete, }) - function setupAutocomplete(): Promise { + const setupAutocomplete = (): Promise => { setupAutocompleteQueue = setupAutocompleteQueue .then(async () => { const config = await getFullConfig() @@ -622,6 +618,10 @@ const register = async ( const autocompleteSetup = setupAutocomplete().catch(() => {}) + // Setup config watcher + configWatcher.onChange(setupAutocomplete, disposables) + await configWatcher.initAndOnChange(ModelsService.onConfigChange, disposables) + if (!isRunningInsideAgent()) { // TODO: The interactive tutorial is currently VS Code specific, both in terms of features and keyboard shortcuts. // Consider opening this up to support dynamic content via Cody Agent. From d7be1fa2658679d8ad72f542abc6cf3f032704bf Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Fri, 12 Jul 2024 14:21:53 -0700 Subject: [PATCH 32/34] fixed callsite --- vscode/src/chat/chat-view/ChatsController.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vscode/src/chat/chat-view/ChatsController.ts b/vscode/src/chat/chat-view/ChatsController.ts index 440b8125008..72550f0f64e 100644 --- a/vscode/src/chat/chat-view/ChatsController.ts +++ b/vscode/src/chat/chat-view/ChatsController.ts @@ -405,8 +405,7 @@ export class ChatsController implements vscode.Disposable { private createChatController(): ChatController { const authStatus = this.options.authProvider.getAuthStatus() const isConsumer = authStatus.isDotCom - const isCodyProUser = !authStatus.userCanUpgrade - const models = ModelsService.getModels(ModelUsage.Chat, isCodyProUser) + const models = ModelsService.getModels(ModelUsage.Chat, authStatus) // Enterprise context is used for remote repositories context fetching // in vs cody extension it should be always off if extension is connected From b85268de3d2721b770ada33b79db00399be23a4f Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Fri, 12 Jul 2024 15:47:27 -0700 Subject: [PATCH 33/34] swapped ordering of setting default models --- vscode/src/chat/chat-view/ChatController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode/src/chat/chat-view/ChatController.ts b/vscode/src/chat/chat-view/ChatController.ts index f9ed0ff3f00..9000ee2605e 100644 --- a/vscode/src/chat/chat-view/ChatController.ts +++ b/vscode/src/chat/chat-view/ChatController.ts @@ -312,10 +312,10 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv this.handleAbort() break case 'chatModel': - this.handleSetChatModel(message.model) // Because this was a user action to change the model we will set that // as a global default for chat await ModelsService.setDefaultModel(ModelUsage.Chat, message.model) + this.handleSetChatModel(message.model) break case 'get-chat-models': this.postChatModels() From 47cd1fe80188e821afaafa7c4a00a18ca3ea95d7 Mon Sep 17 00:00:00 2001 From: jamesmcnamara Date: Fri, 12 Jul 2024 15:49:58 -0700 Subject: [PATCH 34/34] added comment --- vscode/webviews/components/modelSelectField/ModelSelectField.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx index c7d90c898a9..cd3478fcf4c 100644 --- a/vscode/webviews/components/modelSelectField/ModelSelectField.tsx +++ b/vscode/webviews/components/modelSelectField/ModelSelectField.tsx @@ -43,6 +43,7 @@ export const ModelSelectField: React.FunctionComponent<{ }) => { const telemetryRecorder = useTelemetryRecorder() + // The first model is the always the default. const selectedModel = models[0] const isCodyProUser = userInfo.isDotComUser && userInfo.isCodyProUser