fix(chat): guard abort and early idle races
This commit is contained in:
+7
-1
@@ -49,6 +49,8 @@ const envSchema = z
|
||||
OPENCODE_SKILLS_ROOT_DIR: z.string().default("./.opencode/skills"),
|
||||
// client 模式下,目标 opencode server 的基础地址。
|
||||
OPENCODE_CLIENT_BASE_URL: z.string().url().optional(),
|
||||
// 旧版 client 模式环境变量名,保留兼容,解析时会映射到 OPENCODE_CLIENT_BASE_URL。
|
||||
OPENCODE_BASE_URL: z.string().url().optional(),
|
||||
// tjwater-cli 可执行文件路径。
|
||||
TJWATER_CLI_PATH: z.string().default("./cli/tjwater-cli"),
|
||||
// TJWater 后端 API 的基础地址。
|
||||
@@ -122,7 +124,11 @@ const normalizedEnv = {
|
||||
...process.env,
|
||||
OPENCODE_MODE:
|
||||
process.env.OPENCODE_MODE ??
|
||||
(process.env.OPENCODE_CLIENT_BASE_URL ? "client" : "embedded"),
|
||||
(process.env.OPENCODE_CLIENT_BASE_URL || process.env.OPENCODE_BASE_URL
|
||||
? "client"
|
||||
: "embedded"),
|
||||
OPENCODE_CLIENT_BASE_URL:
|
||||
process.env.OPENCODE_CLIENT_BASE_URL ?? process.env.OPENCODE_BASE_URL,
|
||||
};
|
||||
|
||||
export const config: AppConfig = envSchema.parse(normalizedEnv);
|
||||
|
||||
@@ -323,6 +323,7 @@ export const streamPromptResponse = async ({
|
||||
let firstToolEventLogged = false;
|
||||
let lastSessionStatus: string | null = null;
|
||||
let lastSessionStatusMessage: string | null = null;
|
||||
let sawResponseActivity = false;
|
||||
let emittedText = false;
|
||||
let toolCallCount = 0;
|
||||
let done = false;
|
||||
@@ -529,6 +530,7 @@ export const streamPromptResponse = async ({
|
||||
}
|
||||
|
||||
if (isSkillEvent(event)) {
|
||||
sawResponseActivity = true;
|
||||
const { name, reason, payload } = extractSkillAuditInfo(event);
|
||||
logDevelopmentDebug("skill event received", {
|
||||
...debugContext,
|
||||
@@ -552,7 +554,15 @@ export const streamPromptResponse = async ({
|
||||
});
|
||||
}
|
||||
|
||||
if (event.type === "message.updated") {
|
||||
if (event.properties.info.role === "assistant") {
|
||||
sawResponseActivity = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event.type === "message.part.delta" && event.properties.field === "text") {
|
||||
sawResponseActivity = true;
|
||||
const partType = partTypes.get(event.properties.partID);
|
||||
if (partType === "text") {
|
||||
if (!firstTokenLogged) {
|
||||
@@ -591,6 +601,7 @@ export const streamPromptResponse = async ({
|
||||
}
|
||||
|
||||
if (event.type === "message.part.updated") {
|
||||
sawResponseActivity = true;
|
||||
const part = event.properties.part;
|
||||
partTypes.set(part.id, part.type);
|
||||
if (part.type === "text") {
|
||||
@@ -720,6 +731,7 @@ export const streamPromptResponse = async ({
|
||||
}
|
||||
|
||||
if (event.type === "todo.updated") {
|
||||
sawResponseActivity = true;
|
||||
const completed = event.properties.todos.filter(
|
||||
(todo) => todo.status === "completed",
|
||||
).length;
|
||||
@@ -736,6 +748,7 @@ export const streamPromptResponse = async ({
|
||||
}
|
||||
|
||||
if (event.type === "session.error") {
|
||||
sawResponseActivity = true;
|
||||
logDevelopmentDebug("session error received", {
|
||||
...debugContext,
|
||||
elapsedMs: Math.max(0, Date.now() - requestStartedAt),
|
||||
@@ -757,6 +770,13 @@ export const streamPromptResponse = async ({
|
||||
}
|
||||
|
||||
if (event.type === "session.idle") {
|
||||
if (!sawResponseActivity) {
|
||||
logDevelopmentDebug("ignoring session idle before response activity", {
|
||||
...debugContext,
|
||||
elapsedMs: Math.max(0, Date.now() - requestStartedAt),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
logDevelopmentDebug("session idle received", {
|
||||
...debugContext,
|
||||
emittedText,
|
||||
@@ -832,8 +852,10 @@ export const streamPromptResponse = async ({
|
||||
return { aborted: false, failed: false, toolCallCount };
|
||||
} finally {
|
||||
await iterator.return?.(undefined);
|
||||
if (!promptSettled) {
|
||||
if (!promptSettled && !aborted) {
|
||||
await promptPromise.catch(() => undefined);
|
||||
} else if (!promptSettled) {
|
||||
void promptPromise.catch(() => undefined);
|
||||
}
|
||||
logDevelopmentDebug("chat stream cleanup finished", {
|
||||
...debugContext,
|
||||
|
||||
Reference in New Issue
Block a user