fix(opencode): prevent event stream starvation for slash commands
This commit is contained in:
@@ -532,18 +532,19 @@ export class OpenCodeAgentClient implements AgentClient {
|
|||||||
|
|
||||||
for (const [modelId, model] of Object.entries(provider.models)) {
|
for (const [modelId, model] of Object.entries(provider.models)) {
|
||||||
const rawVariants = model.variants ? Object.keys(model.variants) : [];
|
const rawVariants = model.variants ? Object.keys(model.variants) : [];
|
||||||
const thinkingOptions = [
|
const thinkingOptions = rawVariants.map((id, index) => ({
|
||||||
{ id: "default", label: "Model default", isDefault: true },
|
id,
|
||||||
...rawVariants.map((id) => ({ id, label: id })),
|
label: id,
|
||||||
];
|
isDefault: index === 0,
|
||||||
|
}));
|
||||||
|
|
||||||
models.push({
|
models.push({
|
||||||
provider: "opencode",
|
provider: "opencode",
|
||||||
id: `${provider.id}/${modelId}`,
|
id: `${provider.id}/${modelId}`,
|
||||||
label: model.name,
|
label: model.name,
|
||||||
description: `${provider.name} - ${model.family ?? ""}`.trim(),
|
description: `${provider.name} - ${model.family ?? ""}`.trim(),
|
||||||
thinkingOptions: thinkingOptions.length > 1 ? thinkingOptions : undefined,
|
thinkingOptions: thinkingOptions.length > 0 ? thinkingOptions : undefined,
|
||||||
defaultThinkingOptionId: "default",
|
defaultThinkingOptionId: thinkingOptions[0]?.id,
|
||||||
metadata: {
|
metadata: {
|
||||||
providerId: provider.id,
|
providerId: provider.id,
|
||||||
providerName: provider.name,
|
providerName: provider.name,
|
||||||
@@ -1183,14 +1184,18 @@ class OpenCodeAgentSession implements AgentSession {
|
|||||||
const parts = this.buildPromptParts(prompt);
|
const parts = this.buildPromptParts(prompt);
|
||||||
const model = this.parseModel(this.config.model);
|
const model = this.parseModel(this.config.model);
|
||||||
const thinkingOptionId = this.config.thinkingOptionId;
|
const thinkingOptionId = this.config.thinkingOptionId;
|
||||||
const effectiveVariant =
|
const effectiveVariant = thinkingOptionId ?? undefined;
|
||||||
thinkingOptionId && thinkingOptionId !== "default" ? thinkingOptionId : undefined;
|
|
||||||
const effectiveMode = normalizeOpenCodeModeId(this.currentMode);
|
const effectiveMode = normalizeOpenCodeModeId(this.currentMode);
|
||||||
|
|
||||||
let promptResponse;
|
const turnId = this.createTurnId();
|
||||||
|
this.activeForegroundTurnId = turnId;
|
||||||
|
void this.consumeEventStream(turnId, turnAbortController);
|
||||||
|
|
||||||
const slashCommand = await this.resolveSlashCommandInvocation(prompt);
|
const slashCommand = await this.resolveSlashCommandInvocation(prompt);
|
||||||
if (slashCommand) {
|
if (slashCommand) {
|
||||||
promptResponse = await this.client.session.command({
|
// command() blocks until completion, but events stream via SSE in the
|
||||||
|
// background — fire without awaiting so the event stream isn't starved.
|
||||||
|
void this.client.session.command({
|
||||||
sessionID: this.sessionId,
|
sessionID: this.sessionId,
|
||||||
directory: this.config.cwd,
|
directory: this.config.cwd,
|
||||||
command: slashCommand.commandName,
|
command: slashCommand.commandName,
|
||||||
@@ -1198,9 +1203,17 @@ class OpenCodeAgentSession implements AgentSession {
|
|||||||
...(this.config.model ? { model: this.config.model } : {}),
|
...(this.config.model ? { model: this.config.model } : {}),
|
||||||
...(effectiveMode ? { agent: effectiveMode } : {}),
|
...(effectiveMode ? { agent: effectiveMode } : {}),
|
||||||
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.error) {
|
||||||
|
const errorMsg = normalizeTurnFailureError(response.error);
|
||||||
|
this.finishForegroundTurn(
|
||||||
|
{ type: "turn_failed", provider: "opencode", error: errorMsg },
|
||||||
|
turnId,
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
promptResponse = await this.client.session.promptAsync({
|
const promptResponse = await this.client.session.promptAsync({
|
||||||
sessionID: this.sessionId,
|
sessionID: this.sessionId,
|
||||||
directory: this.config.cwd,
|
directory: this.config.cwd,
|
||||||
parts,
|
parts,
|
||||||
@@ -1217,22 +1230,18 @@ class OpenCodeAgentSession implements AgentSession {
|
|||||||
...(effectiveMode ? { agent: effectiveMode } : {}),
|
...(effectiveMode ? { agent: effectiveMode } : {}),
|
||||||
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (promptResponse.error) {
|
if (promptResponse.error) {
|
||||||
const errorMsg = normalizeTurnFailureError(promptResponse.error);
|
const errorMsg = normalizeTurnFailureError(promptResponse.error);
|
||||||
this.notifySubscribers({
|
this.notifySubscribers({
|
||||||
type: "turn_failed",
|
type: "turn_failed",
|
||||||
provider: "opencode",
|
provider: "opencode",
|
||||||
error: errorMsg,
|
error: errorMsg,
|
||||||
});
|
});
|
||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const turnId = this.createTurnId();
|
|
||||||
this.activeForegroundTurnId = turnId;
|
|
||||||
void this.consumeEventStream(turnId, turnAbortController);
|
|
||||||
|
|
||||||
return { turnId };
|
return { turnId };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user