fix: surface config startup failures
This commit is contained in:
@@ -102,16 +102,23 @@ export const Config: z<Config> = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Compose the spine with the stdio front door. The console logger comes first
|
||||
* (infra), then the agent-core bundle pre-creating one agent from this app's
|
||||
* `model`/`resumeSessionId` with the deployment `persona`, then the JSONL
|
||||
* backend, then the readline UI rendering that object as `main`. The `hmr` dev-reload plugin is
|
||||
* a leaf concern (see the module doc), so it is not mounted here.
|
||||
* Compose the spine with the stdio front door. Console logging, persistence,
|
||||
* and user interaction mount first; the readline UI then waits on the agent
|
||||
* registry and subscribes to config-start failures before agent-core can start
|
||||
* the configured identity. The ask-user tool waits on the completed spine.
|
||||
* The `hmr` dev-reload plugin is a leaf concern (see the module doc), so it is
|
||||
* not mounted here.
|
||||
*/
|
||||
export function apply(ctx: Context, config: Config): void {
|
||||
const resumeSessionId = config.resumeSessionId === '' ? undefined : config.resumeSessionId
|
||||
const sessionId = SessionId(resumeSessionId ?? `main-session-${randomUUID()}`)
|
||||
ctx.plugin(ConsoleExporter)
|
||||
ctx.plugin(SessionPersistenceJsonl, { root: config.persistenceRoot ?? './.sessions' })
|
||||
ctx.plugin(UserInteractionService)
|
||||
ctx.plugin(uiStdio, {
|
||||
welcome: config.welcome ?? 'ready.',
|
||||
sessionId,
|
||||
})
|
||||
ctx.plugin(agentCore, {
|
||||
...config.persona !== undefined ? { persona: config.persona } : {},
|
||||
...config.toolOrder !== undefined ? { toolOrder: config.toolOrder } : {},
|
||||
@@ -124,11 +131,5 @@ export function apply(ctx: Context, config: Config): void {
|
||||
}],
|
||||
...config.skills !== undefined ? { skills: config.skills } : {},
|
||||
})
|
||||
ctx.plugin(SessionPersistenceJsonl, { root: config.persistenceRoot ?? './.sessions' })
|
||||
ctx.plugin(UserInteractionService)
|
||||
ctx.plugin(toolAskUser)
|
||||
ctx.plugin(uiStdio, {
|
||||
welcome: config.welcome ?? 'ready.',
|
||||
sessionId,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import type { Readable, Writable } from 'node:stream'
|
||||
import type { Context } from 'cordis'
|
||||
import z from 'schemastery'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import type {} from '@deepseek-ai/dsh-agent-loop'
|
||||
import {
|
||||
UserInteractionError,
|
||||
type AskUserQuestionAnswer,
|
||||
@@ -173,6 +174,7 @@ export function createStdioChat(ctx: Context, config: Config, runtime: StdioRunt
|
||||
const queuedInput: string[] = []
|
||||
let targetReady = target !== undefined
|
||||
let hadReadyTarget = targetReady
|
||||
let failedStartup: { error: unknown } | undefined
|
||||
|
||||
const submit = (agent: Agent, text: string): void => {
|
||||
submittedWork = true
|
||||
@@ -187,6 +189,7 @@ export function createStdioChat(ctx: Context, config: Config, runtime: StdioRunt
|
||||
if (!matchesConfiguredIdentity(agent)) return
|
||||
target = agent
|
||||
targetReady = false
|
||||
failedStartup = undefined
|
||||
})
|
||||
const disposeSessionStartListener = ctx.on('agent/session-start', (agent) => {
|
||||
if (agent !== target) return
|
||||
@@ -220,6 +223,18 @@ export function createStdioChat(ctx: Context, config: Config, runtime: StdioRunt
|
||||
exitTimer = setTimeout(() => { exit(0) }, 200)
|
||||
}
|
||||
|
||||
const disposeStartupFailedListener = ctx.on('agent-loop/config-start-failed', (sessionId, error) => {
|
||||
if (sessionId !== config.sessionId || targetReady) return
|
||||
failedStartup = { error }
|
||||
const dropped = queuedInput.length
|
||||
queuedInput.length = 0
|
||||
submittedWork = sawRunning
|
||||
if (dropped > 0) {
|
||||
ctx.logger.error(`ui-stdio: main agent failed to start; dropped queued stdin (${dropped} line(s)): ${String(error)}`)
|
||||
}
|
||||
maybeExit()
|
||||
})
|
||||
|
||||
const disposeStatusListener = ctx.on('agent/status', (subject, status) => {
|
||||
if (subject !== target) return
|
||||
if (status === 'running') sawRunning = true
|
||||
@@ -374,6 +389,10 @@ export function createStdioChat(ctx: Context, config: Config, runtime: StdioRunt
|
||||
}
|
||||
const text = line.trim()
|
||||
if (!text) return
|
||||
if (failedStartup !== undefined) {
|
||||
ctx.logger.error(`ui-stdio: main agent failed to start; dropped queued stdin (1 line(s)): ${String(failedStartup.error)}`)
|
||||
return
|
||||
}
|
||||
const agent = target
|
||||
if (agent === undefined || !targetReady) {
|
||||
// Initial exact-id restoration is asynchronous. Preserve input until
|
||||
@@ -407,6 +426,7 @@ export function createStdioChat(ctx: Context, config: Config, runtime: StdioRunt
|
||||
disposeCreatedListener()
|
||||
disposeSessionStartListener()
|
||||
disposeDisposedListener()
|
||||
disposeStartupFailedListener()
|
||||
reader.close()
|
||||
}
|
||||
}, 'ui-stdio')
|
||||
|
||||
Reference in New Issue
Block a user