From 7d7b0f0fc79d98e4af3c0102b647c1ee68c947e4 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Tue, 7 Jul 2026 12:03:12 -0400 Subject: [PATCH] fix: Codex round 3 + real Skip semantics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Skip now ANSWERS instead of hiding UI (danny): it resumes the run with a decline notice ('The user chose not to answer this question.') so the model moves on — a client-side dismiss left the run paused until expiry, a hung turn. × / Escape remain pure dismiss (switch to the inline card surface). - P1 (resumed approval tool indices): resumed tool_calls steps whose tool_call id matches a seeded UNRESOLVED part now rebind to that seeded slot instead of offsetting — the original part resolves in place (output attaches) and no duplicate appears; message steps keep the offset, so the text-loss fix stands. createContentIndexOffsetHandlers now takes the seed array; resolved seeded calls are not rebind targets. - P2 (stale selection across questions): selection state resets when the live actionId changes; the vestigial inline-Other state ('other' selection + text atom) is gone — the composer owns free-form. - P2 (Redis abort path loses the args stamp): the abort route re-stamps the question onto the ask tool_call in the reconstructed abort content, so a Stop-abandoned question persists with its question intact. - P2 (malformed args crash): parseAskUserQuestionArgs normalizes untrusted shapes (options: {} / non-string entries) instead of throwing in render. --- api/server/controllers/agents/client.js | 2 +- api/server/routes/agents/index.js | 11 ++- .../Chat/Input/AskUserQuestionPopover.tsx | 4 +- client/src/hooks/Input/useAskAnswerMode.ts | 88 ++++++++++--------- client/src/utils/approval.ts | 24 ++++- packages/api/src/agents/hitl/resume.spec.ts | 47 ++++++++-- packages/api/src/agents/hitl/resume.ts | 45 ++++++++-- 7 files changed, 161 insertions(+), 60 deletions(-) diff --git a/api/server/controllers/agents/client.js b/api/server/controllers/agents/client.js index d8c528fd91..7cb265464e 100644 --- a/api/server/controllers/agents/client.js +++ b/api/server/controllers/agents/client.js @@ -1920,7 +1920,7 @@ class AgentClient extends BaseClient { // type mismatch, is silently dropped against) the pre-pause content. customHandlers: createContentIndexOffsetHandlers( this.options.eventHandlers, - Array.isArray(seedContent) ? seedContent.length : 0, + Array.isArray(seedContent) ? seedContent : [], ), requestBody: config.configurable.requestBody, user: createSafeUser(this.options.req?.user), diff --git a/api/server/routes/agents/index.js b/api/server/routes/agents/index.js index f479ab4b3d..a4221a3c37 100644 --- a/api/server/routes/agents/index.js +++ b/api/server/routes/agents/index.js @@ -8,6 +8,7 @@ const { toClientPendingAction, isHITLEnabled, deleteAgentCheckpoint, + attachAskUserQuestionArgs, } = require('@librechat/api'); const { createSseStreamTelemetry } = require('@librechat/api/telemetry'); const { logger } = require('@librechat/data-schemas'); @@ -318,7 +319,15 @@ router.post('/chat/abort', configMiddleware, async (req, res) => { abortResult.jobData?.responseMessageId && hasPersistableAbortContent(abortResult.content) ) { - const { jobData, content, text } = abortResult; + const { jobData, text } = abortResult; + let { content } = abortResult; + // Redis reconstructs abort content from the graph/chunk log, which never saw + // the pause-time args stamp applied to the in-process contentParts — re-stamp + // here so a question abandoned via Stop persists with its question intact. + const abortedPayload = job.metadata?.pendingAction?.payload; + if (abortedPayload?.type === 'ask_user_question' && Array.isArray(content)) { + content = attachAskUserQuestionArgs(content, abortedPayload.question); + } const responseMessage = { messageId: jobData.responseMessageId, parentMessageId: jobData.userMessage.messageId, diff --git a/client/src/components/Chat/Input/AskUserQuestionPopover.tsx b/client/src/components/Chat/Input/AskUserQuestionPopover.tsx index 880be0d70b..87fc0bdc3a 100644 --- a/client/src/components/Chat/Input/AskUserQuestionPopover.tsx +++ b/client/src/components/Chat/Input/AskUserQuestionPopover.tsx @@ -14,7 +14,7 @@ import { cn } from '~/utils'; */ function AskUserQuestionPopoverContent({ conversationId }: { conversationId: string }) { const localize = useLocalize(); - const { liveAsk, active, options, selected, setSelected, canSubmit, submit, dismiss } = + const { liveAsk, active, options, selected, setSelected, canSubmit, submit, skip, dismiss } = useAskAnswerMode(conversationId); if (!active || !liveAsk) { @@ -61,7 +61,7 @@ function AskUserQuestionPopoverContent({ conversationId }: { conversationId: str ))}
-