fix(continuation): skip internal user turns

This commit is contained in:
YeonGyu-Kim
2026-05-15 23:16:23 +09:00
parent c580b8f2ce
commit be25109f6d
10 changed files with 275 additions and 8 deletions
+40 -1
View File
@@ -1,10 +1,49 @@
declare const require: (name: string) => any
const { describe, expect, test } = require("bun:test")
import { extractResumeConfig, resumeSession } from "./resume"
import { OMO_INTERNAL_INITIATOR_MARKER } from "../../shared/internal-initiator-marker"
import { extractResumeConfig, findLastUserMessage, resumeSession } from "./resume"
import type { MessageData } from "./types"
describe("session-recovery resume", () => {
test("findLastUserMessage skips synthetic and internally marked user messages", () => {
// given
const realUserMessage: MessageData = {
info: {
role: "user",
agent: "Sisyphus",
model: { providerID: "openai", modelID: "gpt-5.3-codex" },
},
parts: [{ type: "text", text: "real user task" }],
}
const syntheticUserMessage: MessageData = {
info: {
role: "user",
agent: "Atlas",
model: { providerID: "anthropic", modelID: "claude-sonnet-4-6" },
},
parts: [{ type: "text", text: "synthetic wake", synthetic: true }],
}
const internalUserMessage: MessageData = {
info: {
role: "user",
agent: "Hephaestus",
model: { providerID: "openai", modelID: "gpt-5.4" },
},
parts: [{ type: "text", text: `internal wake\n${OMO_INTERNAL_INITIATOR_MARKER}` }],
}
// when
const result = findLastUserMessage([
realUserMessage,
syntheticUserMessage,
internalUserMessage,
])
// then
expect(result).toBe(realUserMessage)
})
test("extractResumeConfig carries tools from last user message", () => {
// given
const userMessage: MessageData = {
+9 -4
View File
@@ -1,7 +1,11 @@
import type { createOpencodeClient } from "@opencode-ai/sdk"
import type { MessageData, ResumeConfig } from "./types"
import { createInternalAgentContinuationTextPart, resolveInheritedPromptTools } from "../../shared"
import {
createInternalAgentContinuationTextPart,
isRealUserMessage,
resolveInheritedPromptTools,
} from "../../shared"
import { promptAsyncAfterSessionIdle } from "../shared/prompt-async-gate"
import type { MessageData, ResumeConfig } from "./types"
const RECOVERY_RESUME_TEXT = "[session recovered - continuing previous task]"
@@ -9,8 +13,9 @@ type Client = ReturnType<typeof createOpencodeClient>
export function findLastUserMessage(messages: MessageData[]): MessageData | undefined {
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].info?.role === "user") {
return messages[i]
const message = messages[i]
if (message !== undefined && isRealUserMessage(message)) {
return message
}
}
return undefined
+1
View File
@@ -82,6 +82,7 @@ export interface MessageData {
type: string
id?: string
text?: string
synthetic?: boolean
thinking?: string
name?: string
input?: Record<string, unknown>