fix(stdio): close startup failure gaps
This commit is contained in:
@@ -20,17 +20,26 @@ export async function main(boot: SdkBootContext) {
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
const ctx = await startSDK(new URL('./cordis.yml', import.meta.url))
|
const ctx = await startSDK(new URL('./cordis.yml', import.meta.url))
|
||||||
{{#if isStdio}}
|
{{#if isStdio}}
|
||||||
if (resume === undefined) {
|
try {
|
||||||
await ctx.agents.create({
|
if (resume === undefined) {
|
||||||
sessionId,
|
await ctx.agents.create({
|
||||||
meta: { cwd: boot.cwd },
|
sessionId,
|
||||||
agentOptions: { model },
|
meta: { cwd: boot.cwd },
|
||||||
})
|
agentOptions: { model },
|
||||||
} else {
|
})
|
||||||
await ctx.agents.resume({
|
} else {
|
||||||
resumeSessionId: sessionId,
|
await ctx.agents.resume({
|
||||||
agentOptions: { model },
|
resumeSessionId: sessionId,
|
||||||
})
|
agentOptions: { model },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
try {
|
||||||
|
await ctx.fiber.dispose()
|
||||||
|
} catch (disposeError) {
|
||||||
|
throw new AggregateError([error, disposeError], 'stdio startup and cleanup failed')
|
||||||
|
}
|
||||||
|
throw error
|
||||||
}
|
}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if isEmbed}}
|
{{#if isEmbed}}
|
||||||
|
|||||||
@@ -171,6 +171,8 @@ describe('SdkProject and ProjectEditSession', () => {
|
|||||||
expect(index).toContain('const sessionId = SessionId(resume ?? `main-session-${randomUUID()}`)')
|
expect(index).toContain('const sessionId = SessionId(resume ?? `main-session-${randomUUID()}`)')
|
||||||
expect(index).toContain('process.env.DSH_SDK_SESSION_ID = sessionId')
|
expect(index).toContain('process.env.DSH_SDK_SESSION_ID = sessionId')
|
||||||
expect(index).toContain('resumeSessionId: sessionId')
|
expect(index).toContain('resumeSessionId: sessionId')
|
||||||
|
expect(index).toContain('await ctx.fiber.dispose()')
|
||||||
|
expect(index).toContain("new AggregateError([error, disposeError], 'stdio startup and cleanup failed')")
|
||||||
expect(project.packageManifest().scripts).toEqual({
|
expect(project.packageManifest().scripts).toEqual({
|
||||||
dev: 'dsh-sdk dev index.ts -- --model="deepseek-v4-flash"',
|
dev: 'dsh-sdk dev index.ts -- --model="deepseek-v4-flash"',
|
||||||
build: 'dsh-sdk build',
|
build: 'dsh-sdk build',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ This package owns the terminal channel only. It injects `agents` and `userIntera
|
|||||||
| Key | Default | Meaning |
|
| Key | Default | Meaning |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `welcome` | `ready.` | Banner printed before the first prompt |
|
| `welcome` | `ready.` | Banner printed before the first prompt |
|
||||||
| `agent` | `main` | Agent id driven by stdin and observed for EOF shutdown |
|
| `sessionId` | `main` | Exact agent/session identity driven by stdin and observed for EOF shutdown |
|
||||||
|
|
||||||
The plugin seeds display labels from the live agent registry, then tracks `agent/created` and `agent/disposed` so HMR and externally managed agents render consistently. Disposal closes readline and unregisters every listener/provider through Cordis effects.
|
The plugin seeds display labels from the live agent registry, then tracks `agent/created` and `agent/disposed` so HMR and externally managed agents render consistently. Disposal closes readline and unregisters every listener/provider through Cordis effects.
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ The plugin seeds display labels from the live agent registry, then tracks `agent
|
|||||||
name: '@deepseek-ai/dsh-stdio'
|
name: '@deepseek-ai/dsh-stdio'
|
||||||
config:
|
config:
|
||||||
welcome: 'agent REPL ready. Give it a coding task.'
|
welcome: 'agent REPL ready. Give it a coding task.'
|
||||||
agent: main
|
sessionId: main
|
||||||
```
|
```
|
||||||
|
|
||||||
## Model Experience
|
## Model Experience
|
||||||
@@ -37,6 +37,6 @@ The plugin seeds display labels from the live agent registry, then tracks `agent
|
|||||||
|
|
||||||
## Known Limitations and Deferred Work
|
## Known Limitations and Deferred Work
|
||||||
|
|
||||||
- **One configured agent receives stdin** — the session/event renderer can print output from any session, but input lines always drive the configured `agent` id rather than routing by the visible label.
|
- **One configured session receives stdin** — the session/event renderer can print output from any session, but input lines always drive the configured `sessionId` rather than routing by the visible label.
|
||||||
- **Terminal questions are text-only and sequential** — the provider queues asks, supports option labels plus custom text, and has no richer UI shapes such as file pickers or diff previews.
|
- **Terminal questions are text-only and sequential** — the provider queues asks, supports option labels plus custom text, and has no richer UI shapes such as file pickers or diff previews.
|
||||||
- **Closed stdin ends the terminal channel** — EOF rejects active or queued questions and exits after submitted work reaches idle; there is no reconnect path for a long-lived process.
|
- **Closed stdin ends the terminal channel** — EOF rejects active or queued questions and exits after submitted work reaches idle; there is no reconnect path for a long-lived process.
|
||||||
|
|||||||
@@ -29,6 +29,11 @@
|
|||||||
"@deepseek-ai/dsh-user-interaction": "^0.0.1",
|
"@deepseek-ai/dsh-user-interaction": "^0.0.1",
|
||||||
"cordis": "^4.0.0-rc.7"
|
"cordis": "^4.0.0-rc.7"
|
||||||
},
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@deepseek-ai/dsh-agent-loop": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"schemastery": "^3.18.0"
|
"schemastery": "^3.18.0"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user