run: reduce interactive startup overhead

This commit is contained in:
Simon Klee
2026-04-18 10:05:10 +02:00
parent 1bb787cb3c
commit 7816951bdb
3 changed files with 69 additions and 21 deletions

View File

@@ -20,6 +20,30 @@ const DEFAULT_KEYBINDS: FooterKeybinds = {
inputNewline: "shift+return,ctrl+return,alt+return,ctrl+j",
}
let configTask: Promise<Awaited<ReturnType<typeof TuiConfig.get>>> | undefined
function loadConfig() {
if (configTask) {
return configTask
}
const task = TuiConfig.get()
configTask = task
task.then(
() => {
if (configTask === task) {
configTask = undefined
}
},
() => {
if (configTask === task) {
configTask = undefined
}
},
)
return task
}
export type ModelInfo = {
variants: string[]
limits: Record<string, number>
@@ -98,7 +122,7 @@ export async function resolveSessionInfo(
// Always ensures <leader>t is present in the variant cycle binding.
export async function resolveFooterKeybinds(): Promise<FooterKeybinds> {
try {
const config = await TuiConfig.get()
const config = await loadConfig()
const configuredLeader = config.keybinds?.leader?.trim() || DEFAULT_KEYBINDS.leader
const configuredVariantCycle = config.keybinds?.variant_cycle?.trim() || "ctrl+t"
const configuredInterrupt = config.keybinds?.session_interrupt?.trim() || DEFAULT_KEYBINDS.interrupt
@@ -132,7 +156,7 @@ export async function resolveFooterKeybinds(): Promise<FooterKeybinds> {
export async function resolveDiffStyle(): Promise<RunDiffStyle> {
try {
const config = await TuiConfig.get()
const config = await loadConfig()
return config.diff_style ?? "auto"
} catch {
return "auto"

View File

@@ -176,6 +176,7 @@ export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lif
title: splashTitle(input.sessionTitle, input.history),
session_id: input.sessionID,
})
const footerTask = import("./footer")
queueSplash(
renderer,
state,
@@ -189,7 +190,7 @@ export async function createRuntimeLifecycle(input: LifecycleInput): Promise<Lif
)
await renderer.idle().catch(() => {})
const { RunFooter } = await import("./footer")
const { RunFooter } = await footerTask
const labels = footerLabels({
agent: input.agent,

View File

@@ -83,14 +83,6 @@ async function runInteractiveRuntime(input: RunRuntimeInput): Promise<void> {
variant: undefined,
})
const savedTask = resolveSavedVariant(ctx.model)
const agentsTask = ctx.sdk.app
.agents({ directory: ctx.directory })
.then((x) => x.data ?? [])
.catch(() => [])
const resourcesTask = ctx.sdk.experimental.resource
.list({ directory: ctx.directory })
.then((x) => Object.values(x.data ?? {}))
.catch(() => [])
let variants: string[] = []
let limits: Record<string, number> = {}
let aborting = false
@@ -210,17 +202,48 @@ async function runInteractiveRuntime(input: RunRuntimeInput): Promise<void> {
})
const footer = shell.footer
void Promise.all([agentsTask, resourcesTask]).then(([agents, resources]) => {
if (footer.isClosed) {
return
let catalogTask: Promise<void> | undefined
const loadCatalog = () => {
if (catalogTask) {
return catalogTask
}
footer.event({
type: "catalog",
agents,
resources,
catalogTask = Promise.all([
ctx.sdk.app
.agents({ directory: ctx.directory })
.then((x) => x.data ?? [])
.catch(() => []),
ctx.sdk.experimental.resource
.list({ directory: ctx.directory })
.then((x) => Object.values(x.data ?? {}))
.catch(() => []),
])
.then(([agents, resources]) => {
if (footer.isClosed) {
return
}
footer.event({
type: "catalog",
agents,
resources,
})
})
.catch(() => {})
return catalogTask
}
void footer
.idle()
.then(() => {
if (footer.isClosed) {
return
}
void loadCatalog()
})
})
.catch(() => {})
if (Flag.OPENCODE_SHOW_TTFD) {
footer.append({
@@ -435,12 +458,12 @@ export async function runInteractiveLocalMode(input: RunLocalInput): Promise<voi
return pending
}
pending = Promise.all([input.resolveAgent(), input.session(sdk)]).then(async ([agent, session]) => {
pending = Promise.all([input.resolveAgent(), input.session(sdk)]).then(([agent, session]) => {
if (!session?.id) {
throw new Error("Session not found")
}
await input.share(sdk, session.id)
void input.share(sdk, session.id).catch(() => {})
return {
sessionID: session.id,
sessionTitle: session.title,