Add Maestro login button

This commit is contained in:
Saoud Rizwan
2024-08-22 11:02:25 -04:00
parent e8df2400bf
commit f6fd76823b
18 changed files with 375 additions and 11 deletions

View File

@@ -26,7 +26,8 @@
"react-virtuoso": "^4.7.13",
"rewire": "^7.0.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/react-scroll": "^1.8.10",
@@ -21449,6 +21450,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",

View File

@@ -21,7 +21,8 @@
"react-virtuoso": "^4.7.13",
"rewire": "^7.0.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"zod": "^3.23.8"
},
"scripts": {
"start": "react-scripts start",

View File

@@ -10,6 +10,7 @@ import WelcomeView from "./components/WelcomeView"
import { vscode } from "./utils/vscode"
import HistoryView from "./components/HistoryView"
import { HistoryItem } from "../../src/shared/HistoryItem"
import { MaestroUser } from "../../src/shared/maestro"
/*
The contents of webviews however are created when the webview becomes visible and destroyed when the webview is moved into the background. Any state inside the webview will be lost when the webview is moved to a background tab.
@@ -30,6 +31,7 @@ const App: React.FC = () => {
const [claudeMessages, setClaudeMessages] = useState<ClaudeMessage[]>([])
const [taskHistory, setTaskHistory] = useState<HistoryItem[]>([])
const [showAnnouncement, setShowAnnouncement] = useState(false)
const [maestroUser, setMaestroUser] = useState<MaestroUser | undefined>(undefined)
useEffect(() => {
vscode.postMessage({ type: "webviewDidLaunch" })
@@ -58,6 +60,7 @@ const App: React.FC = () => {
setShowAnnouncement(true)
vscode.postMessage({ type: "didShowAnnouncement" })
}
setMaestroUser(message.state!.maestroUser)
setDidHydrateState(true)
break
case "action":
@@ -100,6 +103,7 @@ const App: React.FC = () => {
<SettingsView
version={version}
apiConfiguration={apiConfiguration}
maestroUser={maestroUser}
setApiConfiguration={setApiConfiguration}
maxRequestsPerTask={maxRequestsPerTask}
setMaxRequestsPerTask={setMaxRequestsPerTask}

View File

@@ -1,4 +1,10 @@
import { VSCodeDropdown, VSCodeLink, VSCodeOption, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import {
VSCodeButton,
VSCodeDropdown,
VSCodeLink,
VSCodeOption,
VSCodeTextField,
} from "@vscode/webview-ui-toolkit/react"
import React, { useMemo } from "react"
import {
ApiConfiguration,
@@ -8,17 +14,27 @@ import {
anthropicModels,
bedrockDefaultModelId,
bedrockModels,
maestroDefaultModelId,
maestroModels,
openRouterDefaultModelId,
openRouterModels,
} from "../../../src/shared/api"
import { vscode } from "../utils/vscode"
import { MaestroUser } from "../../../src/shared/maestro"
interface ApiOptionsProps {
showModelOptions: boolean
apiConfiguration?: ApiConfiguration
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
maestroUser?: MaestroUser
}
const ApiOptions: React.FC<ApiOptionsProps> = ({ showModelOptions, apiConfiguration, setApiConfiguration }) => {
const ApiOptions: React.FC<ApiOptionsProps> = ({
showModelOptions,
apiConfiguration,
setApiConfiguration,
maestroUser,
}) => {
const handleInputChange = (field: keyof ApiConfiguration) => (event: any) => {
setApiConfiguration((prev) => ({ ...prev, [field]: event.target.value }))
}
@@ -69,6 +85,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ showModelOptions, apiConfigurat
<VSCodeOption value="anthropic">Anthropic</VSCodeOption>
<VSCodeOption value="bedrock">AWS Bedrock</VSCodeOption>
<VSCodeOption value="openrouter">OpenRouter</VSCodeOption>
<VSCodeOption value="maestro">Maestro</VSCodeOption>
</VSCodeDropdown>
</div>
@@ -122,6 +139,48 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ showModelOptions, apiConfigurat
</div>
)}
{selectedProvider === "maestro" && (
<>
{maestroUser ? (
<div>
<p
style={{
marginTop: 3,
}}>
<span style={{ fontWeight: 500 }}>Signed in as: </span>
<span style={{ color: "var(--vscode-testing-iconPassed)" }}>{maestroUser.email}</span>
</p>
<div style={{ margin: "4px 0px" }}>
<VSCodeButton
appearance="secondary"
onClick={() => vscode.postMessage({ type: "didClickMaestroSignOut" })}>
Sign out
</VSCodeButton>
</div>
</div>
) : (
<div>
<div style={{ margin: "4px 0px" }}>
<VSCodeButton
appearance="primary"
onClick={() => vscode.postMessage({ type: "didClickMaestroSignIn" })}>
Sign in to Maestro
</VSCodeButton>
</div>
<p
style={{
fontSize: 12,
marginTop: 5,
color: "var(--vscode-descriptionForeground)",
}}>
This will open your browser to sign in to Maestro. You will be redirected back to the
extension after signing in.
</p>
</div>
)}
</>
)}
{selectedProvider === "bedrock" && (
<div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
<VSCodeTextField
@@ -196,6 +255,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ showModelOptions, apiConfigurat
{selectedProvider === "anthropic" && createDropdown(anthropicModels)}
{selectedProvider === "openrouter" && createDropdown(openRouterModels)}
{selectedProvider === "bedrock" && createDropdown(bedrockModels)}
{selectedProvider === "maestro" && createDropdown(maestroModels)}
</div>
<ModelInfoView modelInfo={selectedModelInfo} />
@@ -299,6 +359,8 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration) {
return getProviderData(openRouterModels, openRouterDefaultModelId)
case "bedrock":
return getProviderData(bedrockModels, bedrockDefaultModelId)
case "maestro":
return getProviderData(maestroModels, maestroDefaultModelId)
}
}

View File

@@ -4,10 +4,12 @@ import { ApiConfiguration } from "../../../src/shared/api"
import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate"
import { vscode } from "../utils/vscode"
import ApiOptions from "./ApiOptions"
import { MaestroUser } from "../../../src/shared/maestro"
type SettingsViewProps = {
version: string
apiConfiguration?: ApiConfiguration
maestroUser?: MaestroUser
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
maxRequestsPerTask: string
setMaxRequestsPerTask: React.Dispatch<React.SetStateAction<string>>
@@ -19,6 +21,7 @@ type SettingsViewProps = {
const SettingsView = ({
version,
apiConfiguration,
maestroUser,
setApiConfiguration,
maxRequestsPerTask,
setMaxRequestsPerTask,
@@ -93,6 +96,7 @@ const SettingsView = ({
<div style={{ marginBottom: 5 }}>
<ApiOptions
apiConfiguration={apiConfiguration}
maestroUser={maestroUser}
setApiConfiguration={setApiConfiguration}
showModelOptions={true}
/>

View File

@@ -18,6 +18,11 @@ export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): s
return "You must provide a valid API key or choose a different provider."
}
break
case "maestro":
// if (!apiConfiguration.maestroApiKey) {
// return "You must provide a valid API key or choose a different provider."
// }
break
}
}
return undefined