fix(prompt-gate): harden sync and team prompt dispatch

This commit is contained in:
YeonGyu-Kim
2026-05-19 17:43:37 +09:00
parent 1492bffd20
commit bcea4a9d28
44 changed files with 688 additions and 140 deletions
@@ -567,6 +567,49 @@ describe("createTeamIdleWakeHint", () => {
expect(processedEntries).toContain(`${messageId}.json`)
})
test("#given a pending live-delivery ack and later unread message #when member idles after the live reply #then it wakes the member for the unread message", async () => {
// given
const baseDir = await createTemporaryBaseDir()
const config = createConfig(baseDir)
const teamRunId = randomUUID()
const pendingMessageId = randomUUID()
const unreadMessageId = randomUUID()
await seedRuntimeState(createRuntimeState(teamRunId, [pendingMessageId]), config)
await seedReservedUnreadMessage(teamRunId, config, pendingMessageId, "already live delivered", 100)
await seedUnreadMessage(teamRunId, config, unreadMessageId, "waiting in inbox", 200)
const promptInputs: WakeHintPromptInput[] = []
const promptAsyncSpy = mock(async (input: WakeHintPromptInput) => {
promptInputs.push(input)
return {}
})
const handler = createTeamIdleWakeHint({
directory: "/tmp/project",
client: { session: { promptAsync: promptAsyncSpy } },
}, config)
// when
await handler({
event: {
type: "session.idle",
properties: { sessionID: "member-session" },
},
})
// then
expect(promptAsyncSpy).toHaveBeenCalledTimes(1)
expect(promptInputs[0]?.body.parts[0]?.text).toContain("1 new team messages")
const runtimeState = await loadRuntimeState(teamRunId, config)
expect(runtimeState.members[0]?.pendingInjectedMessageIds).toEqual([])
const inboxDir = getInboxDir(resolveBaseDir(config), teamRunId, "worker")
const processedEntries = await readdir(path.join(inboxDir, "processed"))
expect(processedEntries).toContain(`${pendingMessageId}.json`)
const inboxEntries = await readdir(inboxDir)
expect(inboxEntries).toContain(`${unreadMessageId}.json`)
})
test("acks pending lead messages on idle without sending a wake hint", async () => {
// given
const baseDir = await createTemporaryBaseDir()
@@ -82,6 +82,13 @@ export function createTeamIdleWakeHint(ctx: TeamIdleWakeHintContext, config: Tea
: member
)),
}), config)
log("team idle handled pending live delivery ack", {
event: "team-mode-idle-pending-ack",
teamRunId: runtimeState.teamRunId,
memberName: memberEntry.name,
sessionID,
ackedCount: pendingInjectedMessageIds.length,
})
}
const unreadMessages = await listUnreadMessages(runtimeState.teamRunId, memberEntry.name, config)
@@ -146,6 +153,7 @@ export function createTeamIdleWakeHint(ctx: TeamIdleWakeHintContext, config: Tea
sessionID,
source: "team-idle-wake-hint",
settleMs: options?.idleSettleMs,
queueBehavior: "defer",
input: {
path: { id: sessionID },
body: buildMemberPromptBody(memberEntry, buildWakeHint(unreadMessages.length)),