mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-03 23:43:19 +00:00
* fix: make repository optional when starting a dashboard run
The agent infers and clones the target repo from the task itself, so a
default repo is never actually required to run — but the dashboard 400'd
("no default repository configured") when a user had none set.
Treat repo as optional: _resolve_repo_config returns {} instead of
raising, repo metadata/config are only written when a repo is present,
and the "missing repository metadata" gate on follow-up messages is
dropped. UI hides the repo chip when absent.
* feat: add repo picker to the run prompt bar
Adds an optional, searchable repository selector next to the model picker
on the Agents home prompt bar (Cursor-style). It pre-fills the user's saved
default repo and can be cleared to "No repository" for a repo-less run.
Because the picker now resolves the default on the client, the create
endpoint honors the request value verbatim: _resolve_repo_config just parses
what's sent ({} when empty) instead of falling back to the saved default,
so an explicit "No repository" is respected.
* refactor: match Cursor layout for repo placement
Move the repo selector out of the prompt-box footer to a pill row above
the input (folder + caret, dropdown opens downward); the model picker
stays inside the box. In the thread view, show the thread title and repo
in a header at the top of the chat, with the follow-up input pinned to
the bottom as before.
86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
import { Link } from "@tanstack/react-router"
|
|
import { useEffect, useState } from "react"
|
|
|
|
import type { ModelSelection } from "@/lib/agents/useModelOptions"
|
|
import { AgentPromptBar } from "@/components/agents/AgentPromptBar"
|
|
import { AgentRunCard } from "@/components/agents/AgentRunCard"
|
|
import { SlackConnectDialog } from "@/components/agents/SlackConnectDialog"
|
|
import { Logo } from "@/components/agents/ported/Logo"
|
|
import { useAgentThreads, useCreateAgentThread } from "@/lib/agents/queries"
|
|
import { useModelOptions } from "@/lib/agents/useModelOptions"
|
|
import { useProfile, useRepos } from "@/lib/profile"
|
|
|
|
export function AgentsHome() {
|
|
const threadsQuery = useAgentThreads()
|
|
const createThread = useCreateAgentThread()
|
|
const recentRuns = (threadsQuery.data ?? []).slice(0, 5)
|
|
const { models, defaultSelection } = useModelOptions()
|
|
const [selection, setSelection] = useState<ModelSelection | null>(null)
|
|
|
|
const reposQuery = useRepos()
|
|
const profileQuery = useProfile()
|
|
// undefined = untouched (fall back to the profile default); null = explicitly "no repo".
|
|
const [repoOverride, setRepoOverride] = useState<string | null | undefined>(undefined)
|
|
const repo =
|
|
repoOverride === undefined ? (profileQuery.data?.default_repo ?? null) : repoOverride
|
|
|
|
useEffect(() => {
|
|
if (selection === null && defaultSelection) setSelection(defaultSelection)
|
|
}, [defaultSelection, selection])
|
|
|
|
return (
|
|
<div className="flex min-w-0 flex-1 flex-col overflow-y-auto px-6 py-8">
|
|
<SlackConnectDialog />
|
|
<div className="mx-auto flex w-full max-w-2xl flex-1 flex-col items-center justify-center">
|
|
<div className="flex w-full flex-col items-center gap-6">
|
|
<Logo />
|
|
<AgentPromptBar
|
|
onSubmit={(prompt) =>
|
|
createThread.mutate({
|
|
prompt,
|
|
repo,
|
|
model_id: selection?.modelId ?? null,
|
|
effort: selection?.effort ?? null,
|
|
})
|
|
}
|
|
disabled={createThread.isPending}
|
|
models={models}
|
|
selection={selection ?? defaultSelection}
|
|
onSelectionChange={setSelection}
|
|
repos={reposQuery.data?.repositories}
|
|
selectedRepo={repo}
|
|
onRepoChange={setRepoOverride}
|
|
/>
|
|
</div>
|
|
|
|
<div className="mx-auto mt-6 w-full max-w-[640px] space-y-2">
|
|
{threadsQuery.isLoading ? (
|
|
<p className="text-center text-sm text-[var(--ui-text-dim)]">
|
|
Loading agents…
|
|
</p>
|
|
) : recentRuns.length === 0 ? (
|
|
<AgentsHomeEmptyState />
|
|
) : (
|
|
recentRuns.map((thread) => (
|
|
<AgentRunCard key={thread.id} thread={thread} />
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function AgentsHomeEmptyState() {
|
|
return (
|
|
<div className="flex flex-col items-center gap-3 py-4 text-center">
|
|
<p className="text-sm text-[var(--ui-text-muted)]">No agents yet.</p>
|
|
<Link
|
|
to="/agents"
|
|
className="text-sm font-medium text-[var(--ui-accent)] hover:underline"
|
|
>
|
|
Start your first agent
|
|
</Link>
|
|
</div>
|
|
)
|
|
}
|