mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-24 20:25:36 -04:00
fix(tui): handle undefined agent during initial data load after login
After Anthropic OAuth login, sync.data.agent is empty while data loads. This caused crashes when accessing local.agent.current().name before agents were populated. Changes: - Make agentStore.current nullable with optional chaining on init - Add fallback to first agent in current() when not found - Add early return guards in submit(), cycle(), cycleFavorite(), set() - Add null checks in highlight(), spinnerDef() memos - Use optional chaining in JSX for agent name display
This commit is contained in:
@@ -20,7 +20,7 @@ export function DialogAgent() {
|
||||
return (
|
||||
<DialogSelect
|
||||
title="Select agent"
|
||||
current={local.agent.current().name}
|
||||
current={local.agent.current()?.name ?? ""}
|
||||
options={options()}
|
||||
onSelect={(option) => {
|
||||
local.agent.set(option.value)
|
||||
|
||||
@@ -498,6 +498,10 @@ export function Prompt(props: PromptProps) {
|
||||
promptModelWarning()
|
||||
return
|
||||
}
|
||||
const currentAgent = local.agent.current()
|
||||
if (!currentAgent) {
|
||||
return
|
||||
}
|
||||
const sessionID = props.sessionID
|
||||
? props.sessionID
|
||||
: await (async () => {
|
||||
@@ -533,7 +537,7 @@ export function Prompt(props: PromptProps) {
|
||||
if (store.mode === "shell") {
|
||||
sdk.client.session.shell({
|
||||
sessionID,
|
||||
agent: local.agent.current().name,
|
||||
agent: currentAgent.name,
|
||||
model: {
|
||||
providerID: selectedModel.providerID,
|
||||
modelID: selectedModel.modelID,
|
||||
@@ -554,7 +558,7 @@ export function Prompt(props: PromptProps) {
|
||||
sessionID,
|
||||
command: command.slice(1),
|
||||
arguments: args.join(" "),
|
||||
agent: local.agent.current().name,
|
||||
agent: currentAgent.name,
|
||||
model: `${selectedModel.providerID}/${selectedModel.modelID}`,
|
||||
messageID,
|
||||
variant,
|
||||
@@ -570,7 +574,7 @@ export function Prompt(props: PromptProps) {
|
||||
sessionID,
|
||||
...selectedModel,
|
||||
messageID,
|
||||
agent: local.agent.current().name,
|
||||
agent: currentAgent.name,
|
||||
model: selectedModel,
|
||||
variant,
|
||||
parts: [
|
||||
@@ -690,7 +694,8 @@ export function Prompt(props: PromptProps) {
|
||||
const highlight = createMemo(() => {
|
||||
if (keybind.leader) return theme.border
|
||||
if (store.mode === "shell") return theme.primary
|
||||
return local.agent.color(local.agent.current().name)
|
||||
const agent = local.agent.current()
|
||||
return agent ? local.agent.color(agent.name) : theme.primary
|
||||
})
|
||||
|
||||
const showVariant = createMemo(() => {
|
||||
@@ -701,7 +706,8 @@ export function Prompt(props: PromptProps) {
|
||||
})
|
||||
|
||||
const spinnerDef = createMemo(() => {
|
||||
const color = local.agent.color(local.agent.current().name)
|
||||
const agent = local.agent.current()
|
||||
const color = agent ? local.agent.color(agent.name) : theme.primary
|
||||
return {
|
||||
frames: createFrames({
|
||||
color,
|
||||
@@ -931,7 +937,7 @@ export function Prompt(props: PromptProps) {
|
||||
/>
|
||||
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1}>
|
||||
<text fg={highlight()}>
|
||||
{store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current().name)}{" "}
|
||||
{store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current()?.name ?? "Agent")}{" "}
|
||||
</text>
|
||||
<Show when={store.mode === "normal"}>
|
||||
<box flexDirection="row" gap={1}>
|
||||
|
||||
@@ -36,9 +36,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
const agent = iife(() => {
|
||||
const agents = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent" && !x.hidden))
|
||||
const [agentStore, setAgentStore] = createStore<{
|
||||
current: string
|
||||
current: string | undefined
|
||||
}>({
|
||||
current: agents()[0].name,
|
||||
current: agents()[0]?.name,
|
||||
})
|
||||
const { theme } = useTheme()
|
||||
const colors = createMemo(() => [
|
||||
@@ -54,7 +54,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
return agents()
|
||||
},
|
||||
current() {
|
||||
return agents().find((x) => x.name === agentStore.current)!
|
||||
if (!agentStore.current) return agents()[0]
|
||||
return agents().find((x) => x.name === agentStore.current) ?? agents()[0]
|
||||
},
|
||||
set(name: string) {
|
||||
if (!agents().some((x) => x.name === name))
|
||||
@@ -179,6 +180,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
|
||||
const currentModel = createMemo(() => {
|
||||
const a = agent.current()
|
||||
if (!a) return fallbackModel()
|
||||
return (
|
||||
getFirstValidModel(
|
||||
() => modelStore.model[a.name],
|
||||
@@ -219,6 +221,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
cycle(direction: 1 | -1) {
|
||||
const current = currentModel()
|
||||
if (!current) return
|
||||
const currentAgent = agent.current()
|
||||
if (!currentAgent) return
|
||||
const recent = modelStore.recent
|
||||
const index = recent.findIndex((x) => x.providerID === current.providerID && x.modelID === current.modelID)
|
||||
if (index === -1) return
|
||||
@@ -227,7 +231,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
if (next >= recent.length) next = 0
|
||||
const val = recent[next]
|
||||
if (!val) return
|
||||
setModelStore("model", agent.current().name, { ...val })
|
||||
setModelStore("model", currentAgent.name, { ...val })
|
||||
},
|
||||
cycleFavorite(direction: 1 | -1) {
|
||||
const favorites = modelStore.favorite.filter((item) => isModelValid(item))
|
||||
@@ -239,6 +243,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
})
|
||||
return
|
||||
}
|
||||
const currentAgent = agent.current()
|
||||
if (!currentAgent) return
|
||||
const current = currentModel()
|
||||
let index = -1
|
||||
if (current) {
|
||||
@@ -253,7 +259,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
}
|
||||
const next = favorites[index]
|
||||
if (!next) return
|
||||
setModelStore("model", agent.current().name, { ...next })
|
||||
setModelStore("model", currentAgent.name, { ...next })
|
||||
const uniq = uniqueBy([next, ...modelStore.recent], (x) => `${x.providerID}/${x.modelID}`)
|
||||
if (uniq.length > 10) uniq.pop()
|
||||
setModelStore(
|
||||
@@ -264,6 +270,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
},
|
||||
set(model: { providerID: string; modelID: string }, options?: { recent?: boolean }) {
|
||||
batch(() => {
|
||||
const currentAgent = agent.current()
|
||||
if (!currentAgent) return
|
||||
if (!isModelValid(model)) {
|
||||
toast.show({
|
||||
message: `Model ${model.providerID}/${model.modelID} is not valid`,
|
||||
@@ -272,7 +280,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
})
|
||||
return
|
||||
}
|
||||
setModelStore("model", agent.current().name, model)
|
||||
setModelStore("model", currentAgent.name, model)
|
||||
if (options?.recent) {
|
||||
const uniq = uniqueBy([model, ...modelStore.recent], (x) => `${x.providerID}/${x.modelID}`)
|
||||
if (uniq.length > 10) uniq.pop()
|
||||
@@ -368,6 +376,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
// Automatically update model when agent changes
|
||||
createEffect(() => {
|
||||
const value = agent.current()
|
||||
if (!value) return
|
||||
if (value.model) {
|
||||
if (isModelValid(value.model))
|
||||
model.set({
|
||||
|
||||
Reference in New Issue
Block a user