Merge pull request #4228 from code-yeongyu/fix/delegate-stale-activity

Fix delegate stale timeout activity checks
This commit is contained in:
YeonGyu-Kim
2026-05-21 12:59:11 +09:00
committed by GitHub
9 changed files with 491 additions and 16 deletions
+24 -11
View File
@@ -61,6 +61,7 @@ Original error: ${createResult.error}`
log(`[look_at] Created session: ${sessionID}`)
log(`[look_at] Sending prompt with ${isBase64Input ? "base64 image" : "file"} to session ${sessionID}`)
let promptFailed = false
try {
await promptSyncWithModelSuggestionRetry(ctx.client, {
path: { id: sessionID },
@@ -83,27 +84,39 @@ Original error: ${createResult.error}`
queueBehavior: "defer",
})
} catch (promptError) {
promptFailed = true
log("[look_at] Prompt error (ignored, will still fetch messages):", promptError)
}
let observedMessages: unknown[] | undefined
let observedText: string | undefined
if (typeof ctx.client.session.status === "function") {
await waitForLookAtSessionResult(ctx.client, sessionID)
const waitResult = await waitForLookAtSessionResult(ctx.client, sessionID, {
allowStableIdleWithoutActivity: true,
allowEmptyStableIdleWithoutActivity: promptFailed,
})
observedText = waitResult.outcome.text ?? undefined
if (observedText) {
observedMessages = waitResult.messages
}
}
log(`[look_at] Fetching messages from session ${sessionID}...`)
const messagesResult = await ctx.client.session.messages({
path: { id: sessionID },
})
let messages = observedMessages
if (!messages) {
log(`[look_at] Fetching messages from session ${sessionID}...`)
const messagesResult = await ctx.client.session.messages({
path: { id: sessionID },
})
if (messagesResult.error) {
log("[look_at] Messages error:", messagesResult.error)
return `Error: Failed to get messages: ${messagesResult.error}`
if (messagesResult.error) {
log("[look_at] Messages error:", messagesResult.error)
return `Error: Failed to get messages: ${messagesResult.error}`
}
messages = messagesResult.data
}
const messages = messagesResult.data
log(`[look_at] Got ${messages.length} messages`)
const responseText = extractLatestAssistantText(messages)
const responseText = observedText ?? extractLatestAssistantText(messages)
if (!responseText) {
log("[look_at] No assistant message found")
return "Error: No response from multimodal-looker agent"
+12
View File
@@ -78,6 +78,18 @@ describe("waitForLookAtSessionResult", () => {
expect(result.outcome.text).toBe("done")
})
test("#given session is absent and has no assistant output #when stable idle is allowed #then keeps polling", async () => {
const client = createMockClient([{ data: {} }], [])
await expect(
waitForLookAtSessionResult(unsafeTestValue(client), "ses_test", {
pollIntervalMs: 10,
timeoutMs: 50,
allowStableIdleWithoutActivity: true,
}),
).rejects.toThrow("timed out")
})
test("#given session never becomes idle #when polling exceeds timeout #then rejects", async () => {
const client = createMockClient(
[{ data: { ses_test: { type: "busy" } } }],
+5 -1
View File
@@ -9,6 +9,7 @@ export interface PollOptions {
timeoutMs?: number
abortSignal?: AbortSignal
allowStableIdleWithoutActivity?: boolean
allowEmptyStableIdleWithoutActivity?: boolean
}
const DEFAULT_POLL_INTERVAL_MS = 1000
@@ -136,7 +137,10 @@ export async function waitForLookAtSessionResult(
const canConcludeIdle =
sawNonIdleStatus ||
!status.supported ||
Boolean(options?.allowStableIdleWithoutActivity)
(
Boolean(options?.allowStableIdleWithoutActivity)
&& (outcome.hasAssistant || Boolean(options?.allowEmptyStableIdleWithoutActivity))
)
if (canConcludeIdle && stableIdlePolls >= IDLE_STABILITY_POLLS_REQUIRED) {
return { messages, outcome, statusType }