fix(continuation): skip internal user turns
This commit is contained in:
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -82,6 +82,7 @@ export interface MessageData {
|
||||
type: string
|
||||
id?: string
|
||||
text?: string
|
||||
synthetic?: boolean
|
||||
thinking?: string
|
||||
name?: string
|
||||
input?: Record<string, unknown>
|
||||
|
||||
Reference in New Issue
Block a user