From 4bc65c9d61110ae04a7beaf6cc68c4755524df49 Mon Sep 17 00:00:00 2001 From: LilMGenius Date: Tue, 10 Nov 2026 14:58:44 +0900 Subject: [PATCH] fix(pabcd-state): name the async route when the goal guard denies request_user_input - The goal-mode interview guard's deny reason named no alternative and ended with "silence is not approval", so an agent holding an approval question retried the blocked tool or stopped; it now says to ask with request_user_input_async when exposed, else in text --- CHANGELOG.md | 4 ++++ plugins/codexclaw/components/pabcd-state/dist/goal-gate.js | 2 +- plugins/codexclaw/components/pabcd-state/src/goal-gate.ts | 2 +- .../codexclaw/components/pabcd-state/test/goal-gate.test.ts | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c67637e..e3b91623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to codexclaw are documented here. The format follows ## [Unreleased] +### Fixed + +- The goal-mode interview guard now names the route when it denies `request_user_input` during an active goal: ask with `request_user_input_async` when the host exposes it, otherwise in plain text. Its old reason ended with "silence is not approval" and named no alternative, so an agent with an approval question retried the blocked tool or stopped, and the user saw only "Blocked by hook". + ## [0.2.46] - 2026-10-31 ### Fixed diff --git a/plugins/codexclaw/components/pabcd-state/dist/goal-gate.js b/plugins/codexclaw/components/pabcd-state/dist/goal-gate.js index 5377cf32..81a4d576 100644 --- a/plugins/codexclaw/components/pabcd-state/dist/goal-gate.js +++ b/plugins/codexclaw/components/pabcd-state/dist/goal-gate.js @@ -63,7 +63,7 @@ function cxcInvocation(moduleUrl ) { const REQUEST_USER_INPUT_TOOL = "request_user_input"; const GOAL_MODE_DENY_REASON = - "Blocking Interview / request_user_input denied. Owner: $codexclaw:cxc-dev async-questions.md; silence is not approval."; + "Blocking Interview / request_user_input denied while a goal is active; ask with request_user_input_async if exposed, else in text. Owner: $codexclaw:cxc-dev async-questions.md"; const UPDATE_GOAL_TOOL_NAME = "update_goal"; diff --git a/plugins/codexclaw/components/pabcd-state/src/goal-gate.ts b/plugins/codexclaw/components/pabcd-state/src/goal-gate.ts index e648aa91..d5c7152d 100644 --- a/plugins/codexclaw/components/pabcd-state/src/goal-gate.ts +++ b/plugins/codexclaw/components/pabcd-state/src/goal-gate.ts @@ -63,7 +63,7 @@ function cxcInvocation(moduleUrl: string): string { const REQUEST_USER_INPUT_TOOL = "request_user_input"; const GOAL_MODE_DENY_REASON = - "Blocking Interview / request_user_input denied. Owner: $codexclaw:cxc-dev async-questions.md; silence is not approval."; + "Blocking Interview / request_user_input denied while a goal is active; ask with request_user_input_async if exposed, else in text. Owner: $codexclaw:cxc-dev async-questions.md"; const UPDATE_GOAL_TOOL_NAME = "update_goal"; diff --git a/plugins/codexclaw/components/pabcd-state/test/goal-gate.test.ts b/plugins/codexclaw/components/pabcd-state/test/goal-gate.test.ts index a0c4d7b4..03400956 100644 --- a/plugins/codexclaw/components/pabcd-state/test/goal-gate.test.ts +++ b/plugins/codexclaw/components/pabcd-state/test/goal-gate.test.ts @@ -154,7 +154,7 @@ test("applyGoalModeInterviewGuard: active goal -> deny request_user_input", () = assert.match(hso.additionalContext, /goal-active=active/); assert.match(hso.permissionDecisionReason, /Interview.*request_user_input/); assert.match(hso.permissionDecisionReason, /\$codexclaw:cxc-dev async-questions\.md/); - assert.match(hso.permissionDecisionReason, /silence is not approval/); + assert.match(hso.permissionDecisionReason, /ask with request_user_input_async/); assert.ok(Buffer.byteLength(hso.additionalContext) <= 200); });