Skip to content

Commit

Permalink
Connect migration UI to agent API
Browse files Browse the repository at this point in the history
  • Loading branch information
vovakulikov committed Oct 22, 2024
1 parent 21686fc commit 50cf53d
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 60 deletions.
1 change: 1 addition & 0 deletions lib/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ export {
isNodeResponse,
INCLUDE_EVERYTHING_CONTEXT_FILTERS,
EXCLUDE_EVERYTHING_CONTEXT_FILTERS,
PromptMode,
type BrowserOrNodeResponse,
type LogEventMode,
type ContextFilters,
Expand Down
5 changes: 5 additions & 0 deletions lib/shared/src/misc/rpc/webviewAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export type PromptsMigrationStatus =
| SuccessfulPromptsMigrationStatus
| FailedPromptsMigrationStatus
| PromptsMigrationSkipStatus
| NoPromptsMigrationNeeded

interface InitialPromptsMigrationStatus {
type: 'initial_migration'
Expand Down Expand Up @@ -195,3 +196,7 @@ interface FailedPromptsMigrationStatus {
interface PromptsMigrationSkipStatus {
type: 'migration_skip'
}

interface NoPromptsMigrationNeeded {
type: 'no_migration_needed'
}
11 changes: 10 additions & 1 deletion lib/shared/src/sourcegraph-api/graphql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,22 @@ export interface Prompt {
}

export interface PromptInput {
ownerId: string
owner: string
name: string
description: string
definitionText: string
draft: boolean
autoSubmit: boolean
mode: PromptMode
visibility?: 'PUBLIC' | 'SECRET'
}

export enum PromptMode {
CHAT = 'CHAT',
EDIT = 'EDIT',
INSERT = 'INSERT',
}

interface ContextFiltersResponse {
site: {
codyContextFilters: {
Expand Down
93 changes: 68 additions & 25 deletions vscode/src/chat/chat-view/prompts-migration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
type CodyCommandMode,
type PromptsMigrationStatus,
currentAuthStatusAuthed,
distinctUntilChanged,
Expand All @@ -13,7 +14,9 @@ import {
} from '@sourcegraph/cody-shared'
import { Observable, Subject } from 'observable-fns'

import { PromptMode } from '@sourcegraph/cody-shared'
import { getCodyCommandList } from '../../commands/CommandsController'
import { sleep } from '../../completions/utils'
import { remoteReposForAllWorkspaceFolders } from '../../repository/remoteRepos'
import { localStorage } from '../../services/LocalStorageProvider'

Expand All @@ -38,14 +41,20 @@ export function getPromptsMigrationInfo(): Observable<PromptsMigrationStatus> {
// Don't run migration if you're already run this before (ignore any other new commands
// that had been added after first migration run
const migrationMap = localStorage.get<Record<string, boolean>>(PROMPTS_MIGRATION_KEY) ?? {}
const commands = getCodyCommandList().filter(command => command.type !== 'default')
const commands = [] // getCodyCommandList().filter(command => command.type !== 'default')

if (!repository || migrationMap[repository?.id ?? ''] || commands.length === 0) {
return Observable.of({
if (!repository || migrationMap[repoKey(repository?.id ?? '')]) {
return Observable.of<PromptsMigrationStatus>({
type: 'migration_skip',
})
}

if (commands.length === 0) {
return Observable.of<PromptsMigrationStatus>({
type: 'no_migration_needed',
})
}

return PROMPTS_MIGRATION_RESULT
})
)
Expand Down Expand Up @@ -86,6 +95,8 @@ export async function startPromptsMigration(): Promise<void> {
try {
const prompts = await graphqlClient.queryPrompts(commandKey.replace(/\s+/g, '-'))

await sleep(3000)

// If there is no prompts associated with the command include this
// command to migration
if (prompts.length === 0) {
Expand All @@ -103,39 +114,71 @@ export async function startPromptsMigration(): Promise<void> {
allCommandsToMigrate: commandsToMigrate.length,
})

for (let index = 0; index < commands.length; index++) {
const command = commands[index]
const commandKey = (command.key ?? command.slashCommand).replace(/\s+/g, '-')

const newPrompt = await graphqlClient.createPrompt({
ownerId: currentUserId,
name: `migrated-command-${commandKey}`,
description: `Migrated from command ${commandKey}`,
definitionText: command.prompt,
visibility: 'SECRET',
})
for (let index = 0; index < commandsToMigrate.length; index++) {
try {
const command = commandsToMigrate[index]
const commandKey = (command.key ?? command.slashCommand).replace(/\s+/g, '-')

const newPrompt = await graphqlClient.createPrompt({
owner: currentUserId,
name: commandKey,
description: `Migrated from command ${commandKey}`,
definitionText: command.prompt,
draft: false,
autoSubmit: false,
mode: commandModeToPromptMode(command.mode),
visibility: 'SECRET',
})

await sleep(3000)

// Change prompt visibility to PUBLIC if it's admin performing migration
// TODO: [VK] Remove it and use visibility field in prompt creation (current API limitation)
if (authStatus.siteAdmin) {
await graphqlClient.transferPromptOwnership({ id: newPrompt.id, visibility: 'PUBLIC' })
}

// Change prompt visibility to PUBLIC if it's admin performing migration
// TODO: [VK] Remove it and use visibility field in prompt creation (current API limitation)
if (authStatus.siteAdmin) {
await graphqlClient.transferPromptOwnership({ id: newPrompt.id, visibility: 'PUBLIC' })
PROMPTS_MIGRATION_STATUS.next({
type: 'migrating',
commandsMigrated: index + 1,
allCommandsToMigrate: commandsToMigrate.length,
})
} catch (error: any) {
PROMPTS_MIGRATION_STATUS.next({
type: 'migration_failed',
errorMessage: error.toString(),
})

return
}

PROMPTS_MIGRATION_STATUS.next({
type: 'migrating',
commandsMigrated: index + 1,
allCommandsToMigrate: commandsToMigrate.length,
})
}

const repositories = (await firstResultFromOperation(remoteReposForAllWorkspaceFolders)) ?? []
const repository = repositories[0]

if (repository) {
const migrationMap = localStorage.get<Record<string, boolean>>(PROMPTS_MIGRATION_KEY) ?? {}
migrationMap[repository.id] = true
migrationMap[repoKey(repository.id)] = true
await localStorage.set(PROMPTS_MIGRATION_KEY, migrationMap)
}

PROMPTS_MIGRATION_STATUS.next({ type: 'migration_success' })
}

function commandModeToPromptMode(commandMode?: CodyCommandMode): PromptMode {
switch (commandMode) {
case 'ask':
return PromptMode.CHAT
case 'edit':
return PromptMode.EDIT
case 'insert':
return PromptMode.INSERT

default:
return PromptMode.CHAT
}
}

function repoKey(repositoryId: string) {
return `prefix8-${repositoryId}`
}
4 changes: 4 additions & 0 deletions vscode/src/chat/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ describe('validateAuthStatus', () => {
endpoint: DOTCOM_URL.toString(),
primaryEmail: '[email protected]',
hasVerifiedEmail: true,
siteAdmin: true,
username: 'alice',
organizations: { nodes: [{ id: 'x', name: 'foo' }] },
})
).toStrictEqual<AuthStatus>({
endpoint: DOTCOM_URL.toString(),
authenticated: true,
username: 'alice',
siteAdmin: true,
hasVerifiedEmail: true,
requiresVerifiedEmail: true,
isFireworksTracingEnabled: false,
Expand All @@ -46,13 +48,15 @@ describe('validateAuthStatus', () => {
newAuthStatus({
authenticated: true,
endpoint: 'https://example.com',
siteAdmin: true,
username: 'alice',
})
).toStrictEqual<AuthStatus>({
authenticated: true,
hasVerifiedEmail: false,
endpoint: 'https://example.com',
isFireworksTracingEnabled: false,
siteAdmin: true,
primaryEmail: undefined,
requiresVerifiedEmail: false,
pendingValidation: false,
Expand Down
2 changes: 2 additions & 0 deletions vscode/webviews/AppWrapperForTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export const AppWrapperForTest: FunctionComponent<{ children: ReactNode }> = ({
initialContext: () => Observable.of([]),
hydratePromptMessage: text =>
Observable.of(serializedPromptEditorStateFromText(text)),
promptsMigrationStatus: () => Observable.of({ type: 'no_migration_needed' }),
startPromptsMigration: () => Observable.of(),
detectIntent: () => Observable.of(),
resolvedConfig: () =>
Observable.of({
Expand Down
4 changes: 3 additions & 1 deletion vscode/webviews/chat/components/WelcomeMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PromptList } from '../../components/promptList/PromptList'
import { Button } from '../../components/shadcn/ui/button'
import { useActionSelect } from '../../prompts/PromptsTab'
import { View } from '../../tabs'
import { PromptMigrationWidget } from './../../components/promptsMigration/PromptsMigration'

const localStorageKey = 'chat.welcome-message-dismissed'

Expand All @@ -17,7 +18,8 @@ export const WelcomeMessage: FunctionComponent<WelcomeMessageProps> = ({ setView
const runAction = useActionSelect()

return (
<div className="tw-flex-1 tw-flex tw-flex-col tw-items-start tw-w-full tw-px-6 tw-gap-6 tw-transition-all">
<div className="tw-flex-1 tw-flex tw-flex-col tw-items-start tw-w-full tw-px-6 tw-gap-4 tw-transition-all">
<PromptMigrationWidget dismissible={true} />
<div className="tw-flex tw-flex-col tw-gap-4 tw-w-full">
<PromptList
showSearch={false}
Expand Down
2 changes: 1 addition & 1 deletion vscode/webviews/components/promptList/PromptList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const PromptList: FC<PromptListProps> = props => {
tabIndex={0}
shouldFilter={false}
defaultValue={showInitialSelectedItem ? undefined : 'xxx-no-item'}
className={clsx(styles.list, {
className={clsx(className, styles.list, {
[styles.listChips]: appearanceMode === 'chips-list',
})}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
font-size: 1rem;
font-weight: 500;
margin-bottom: 0.25rem;
color: var(--vscode-dropdown-foreground);
}

.description-text {
margin-bottom: 0.75rem;
line-height: 1rem;
margin-bottom: 0.75rem;
color: var(--vscode-dropdown-foreground);
}

.actions {
Expand Down Expand Up @@ -77,3 +79,9 @@
border-left: 0.5rem solid #d8000c;
font-weight: bold;
}

.close {
padding: 0.25rem;
align-self: flex-start;
margin: -0.25rem -0.25rem 0 auto;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,49 @@ type Story = StoryObj<typeof PromptsMigration>

export const DefaultInitialState: Story = {
args: {
status: 'initial',
isMigrationAvailable: false,
status: { type: 'no_migration_needed' },
},
}

export const InitialStateWithAvailableMigration: Story = {
args: {
status: 'initial',
isMigrationAvailable: true,
status: { type: 'initial_migration' },
},
}

export const LoadingStateScanning: Story = {
args: {
status: 'loading',
migratedPrompts: 0,
promptsToMigrate: undefined,
status: {
type: 'migrating',
commandsMigrated: 0,
allCommandsToMigrate: undefined,
},
},
}

export const LoadingStateMigrating: Story = {
args: {
status: 'loading',
migratedPrompts: 1,
promptsToMigrate: 10,
status: {
type: 'migrating',
commandsMigrated: 0,
allCommandsToMigrate: 10,
},
},
}

export const ErroredStateMigrating: Story = {
args: {
status: 'error',
errorMessage: 'some migration error happened',
status: {
type: 'migration_failed',
errorMessage: 'some migration error happened',
},
},
}

export const SuccessfulStateMigrating: Story = {
args: {
status: 'finished',
status: {
type: 'migration_success',
},
},
}
Loading

0 comments on commit 50cf53d

Please sign in to comment.