fix(continuation): mark atlas resumes synthetic
This commit is contained in:
@@ -168,6 +168,11 @@ describe("injectBoulderContinuation", () => {
|
|||||||
body?: {
|
body?: {
|
||||||
model?: { providerID: string; modelID: string }
|
model?: { providerID: string; modelID: string }
|
||||||
variant?: string
|
variant?: string
|
||||||
|
noReply?: boolean
|
||||||
|
parts?: Array<{
|
||||||
|
synthetic?: boolean
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
}> = []
|
}> = []
|
||||||
const promptAsyncMock = mock(async (request: unknown) => {
|
const promptAsyncMock = mock(async (request: unknown) => {
|
||||||
@@ -219,5 +224,9 @@ describe("injectBoulderContinuation", () => {
|
|||||||
modelID: "claude-sonnet-4-20250514",
|
modelID: "claude-sonnet-4-20250514",
|
||||||
})
|
})
|
||||||
expect(capturedRequests[0]?.body?.variant).toBe("max")
|
expect(capturedRequests[0]?.body?.variant).toBe("max")
|
||||||
|
expect(capturedRequests[0]?.body?.noReply).toBeUndefined()
|
||||||
|
const promptPart = capturedRequests[0]?.body?.parts?.[0]
|
||||||
|
expect(promptPart?.synthetic).toBe(true)
|
||||||
|
expect(promptPart?.metadata?.compaction_continue).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
resolveRegisteredAgentName,
|
resolveRegisteredAgentName,
|
||||||
} from "../../features/claude-code-session-state"
|
} from "../../features/claude-code-session-state"
|
||||||
import { log } from "../../shared/logger"
|
import { log } from "../../shared/logger"
|
||||||
import { createInternalAgentTextPart, resolveInheritedPromptTools } from "../../shared"
|
import { createInternalAgentContinuationTextPart, resolveInheritedPromptTools } from "../../shared"
|
||||||
import { HOOK_NAME } from "./hook-name"
|
import { HOOK_NAME } from "./hook-name"
|
||||||
import { BOULDER_CONTINUATION_PROMPT } from "./system-reminder-templates"
|
import { BOULDER_CONTINUATION_PROMPT } from "./system-reminder-templates"
|
||||||
import { resolveRecentPromptContextForSession } from "./recent-model-resolver"
|
import { resolveRecentPromptContextForSession } from "./recent-model-resolver"
|
||||||
@@ -89,7 +89,7 @@ export async function injectBoulderContinuation(input: {
|
|||||||
...(launchModel ? { model: launchModel } : {}),
|
...(launchModel ? { model: launchModel } : {}),
|
||||||
...(launchVariant ? { variant: launchVariant } : {}),
|
...(launchVariant ? { variant: launchVariant } : {}),
|
||||||
...(inheritedTools ? { tools: inheritedTools } : {}),
|
...(inheritedTools ? { tools: inheritedTools } : {}),
|
||||||
parts: [createInternalAgentTextPart(prompt)],
|
parts: [createInternalAgentContinuationTextPart(prompt)],
|
||||||
},
|
},
|
||||||
query: { directory: ctx.directory },
|
query: { directory: ctx.directory },
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -71,8 +71,26 @@ describe("handleAtlasSessionIdle completion nudge", () => {
|
|||||||
|
|
||||||
writeBoulderState(testDirectory, boulder)
|
writeBoulderState(testDirectory, boulder)
|
||||||
|
|
||||||
const promptRequests: Array<{ body?: { parts?: Array<{ text?: string }> } }> = []
|
const promptRequests: Array<{
|
||||||
const promptAsyncMock = mock(async (request: { body?: { parts?: Array<{ text?: string }> } }) => {
|
body?: {
|
||||||
|
noReply?: boolean
|
||||||
|
parts?: Array<{
|
||||||
|
text?: string
|
||||||
|
synthetic?: boolean
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}> = []
|
||||||
|
const promptAsyncMock = mock(async (request: {
|
||||||
|
body?: {
|
||||||
|
noReply?: boolean
|
||||||
|
parts?: Array<{
|
||||||
|
text?: string
|
||||||
|
synthetic?: boolean
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}) => {
|
||||||
promptRequests.push(request)
|
promptRequests.push(request)
|
||||||
return { data: {} }
|
return { data: {} }
|
||||||
})
|
})
|
||||||
@@ -118,6 +136,9 @@ describe("handleAtlasSessionIdle completion nudge", () => {
|
|||||||
expect(promptText).toContain("- 1 Parse input: 1m 1s")
|
expect(promptText).toContain("- 1 Parse input: 1m 1s")
|
||||||
expect(promptText).toContain("- 2 Save output: 4s")
|
expect(promptText).toContain("- 2 Save output: 4s")
|
||||||
expect(promptText).not.toContain("{ELAPSED_HUMAN}")
|
expect(promptText).not.toContain("{ELAPSED_HUMAN}")
|
||||||
|
expect(promptRequests[0]?.body?.noReply).toBeUndefined()
|
||||||
|
expect(promptRequests[0]?.body?.parts?.[0]?.synthetic).toBe(true)
|
||||||
|
expect(promptRequests[0]?.body?.parts?.[0]?.metadata?.compaction_continue).toBe(true)
|
||||||
|
|
||||||
const persistedState = getState(SESSION_ID)
|
const persistedState = getState(SESSION_ID)
|
||||||
expect(persistedState.boulderCompletionNudgedAt?.[workId]).toBeNumber()
|
expect(persistedState.boulderCompletionNudgedAt?.[workId]).toBeNumber()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
} from "../../features/claude-code-session-state"
|
} from "../../features/claude-code-session-state"
|
||||||
import { getLastAgentFromSession } from "./session-last-agent"
|
import { getLastAgentFromSession } from "./session-last-agent"
|
||||||
import { isSessionInBoulderLineage } from "./boulder-session-lineage"
|
import { isSessionInBoulderLineage } from "./boulder-session-lineage"
|
||||||
import { createInternalAgentTextPart } from "../../shared"
|
import { createInternalAgentContinuationTextPart } from "../../shared"
|
||||||
import { getAgentConfigKey } from "../../shared/agent-display-names"
|
import { getAgentConfigKey } from "../../shared/agent-display-names"
|
||||||
import { log } from "../../shared/logger"
|
import { log } from "../../shared/logger"
|
||||||
import { settleAfterSessionIdle } from "../shared/session-idle-settle"
|
import { settleAfterSessionIdle } from "../shared/session-idle-settle"
|
||||||
@@ -287,7 +287,7 @@ export async function handleAtlasSessionIdle(input: {
|
|||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: {
|
body: {
|
||||||
agent: atlasAgent,
|
agent: atlasAgent,
|
||||||
parts: [createInternalAgentTextPart(prompt)],
|
parts: [createInternalAgentContinuationTextPart(prompt)],
|
||||||
},
|
},
|
||||||
query: { directory: ctx.directory },
|
query: { directory: ctx.directory },
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -74,7 +74,14 @@ describe("session-recovery resume", () => {
|
|||||||
expect(promptBody?.variant).toBe("max")
|
expect(promptBody?.variant).toBe("max")
|
||||||
expect(promptBody?.tools).toEqual({ question: false, bash: true })
|
expect(promptBody?.tools).toEqual({ question: false, bash: true })
|
||||||
expect(Array.isArray(promptBody?.parts)).toBe(true)
|
expect(Array.isArray(promptBody?.parts)).toBe(true)
|
||||||
const firstPart = (promptBody?.parts as Array<{ text?: string }>)?.[0]
|
const firstPart = (promptBody?.parts as Array<{
|
||||||
|
text?: string
|
||||||
|
synthetic?: boolean
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}>)?.[0]
|
||||||
expect(firstPart?.text).toContain(OMO_INTERNAL_INITIATOR_MARKER)
|
expect(firstPart?.text).toContain(OMO_INTERNAL_INITIATOR_MARKER)
|
||||||
|
expect(firstPart?.synthetic).toBe(true)
|
||||||
|
expect(firstPart?.metadata?.compaction_continue).toBe(true)
|
||||||
|
expect(promptBody?.noReply).toBeUndefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { createOpencodeClient } from "@opencode-ai/sdk"
|
import type { createOpencodeClient } from "@opencode-ai/sdk"
|
||||||
import type { MessageData, ResumeConfig } from "./types"
|
import type { MessageData, ResumeConfig } from "./types"
|
||||||
import { createInternalAgentTextPart, resolveInheritedPromptTools } from "../../shared"
|
import { createInternalAgentContinuationTextPart, resolveInheritedPromptTools } from "../../shared"
|
||||||
|
|
||||||
const RECOVERY_RESUME_TEXT = "[session recovered - continuing previous task]"
|
const RECOVERY_RESUME_TEXT = "[session recovered - continuing previous task]"
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export async function resumeSession(client: Client, config: ResumeConfig): Promi
|
|||||||
await client.session.promptAsync({
|
await client.session.promptAsync({
|
||||||
path: { id: config.sessionID },
|
path: { id: config.sessionID },
|
||||||
body: {
|
body: {
|
||||||
parts: [createInternalAgentTextPart(RECOVERY_RESUME_TEXT)],
|
parts: [createInternalAgentContinuationTextPart(RECOVERY_RESUME_TEXT)],
|
||||||
agent: config.agent,
|
agent: config.agent,
|
||||||
...(launchModel ? { model: launchModel } : {}),
|
...(launchModel ? { model: launchModel } : {}),
|
||||||
...(launchVariant ? { variant: launchVariant } : {}),
|
...(launchVariant ? { variant: launchVariant } : {}),
|
||||||
|
|||||||
Reference in New Issue
Block a user