Skip to content

fix(executor): align interactive form defer handling - #2594

Merged
qdaxb merged 1 commit into
mainfrom
fix/claudecode-interactive-form-defer
Aug 11, 2026
Merged

fix(executor): align interactive form defer handling#2594
qdaxb merged 1 commit into
mainfrom
fix/claudecode-interactive-form-defer

Conversation

@qdaxb

@qdaxb qdaxb commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

What changed

  • align Rust Claude Code deferred interactive-form handling with the previous Python executor semantics
  • discard a resumed defer only when its interactive-form tool_use_id matches the form that was just answered
  • preserve a different-ID deferred form as a new clarification request
  • extend the existing executor E2E flow to cover submitted options and consecutive clarification forms
  • add Rust runtime contract coverage and document the defer identity rule

Root cause

The Rust executor treated any deferred form returned with non-empty completed content after an interactive answer as stale. That condition was broader than the Python implementation, which scoped stale resume output by the answered form's tool_use_id. As a result, a legitimate second clarification could be swallowed.

Validation

  • cargo fmt --check
  • cargo test --test agent_runtime_capabilities_contract
  • cargo test --test agent_command_contract
  • cargo test --test interactive_mcp_contract
  • focused frontend E2E mock Jest tests
  • Prettier and ESLint for the changed E2E files
  • full repository pre-push Frontend checks, executor library tests, and Clippy

GitHub CI is expected to run the real executor E2E scenario because the local Docker runtime could not start new containers.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Claude interactive-form session recovery so previously answered forms are not repeated.
    • Follow-up forms with new requests are now preserved and presented for user input, even when accompanied by text.
    • Improved handling of consecutive form submissions and resumed conversations.
    • Preserved the correct order of answers across multiple interactive-form requests.
  • Documentation

    • Clarified interactive-form recovery and deferred request behavior in the architecture guides.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a581470-cee6-484c-b960-8d119efc2456

📥 Commits

Reviewing files that changed from the base of the PR and between 27737b2 and 79334ec.

📒 Files selected for processing (1)
  • frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts

📝 Walkthrough

Walkthrough

Claude deferred-form handling now distinguishes stale answered forms from later clarification forms by interactive-form type and tool_use_id. Executor tests, Anthropic mock streaming, and ClaudeCode end-to-end tests cover single and consecutive form submissions.

Changes

Claude interactive-form resume

Layer / File(s) Summary
Deferred-form handling and contract coverage
executor/src/process/mod.rs, executor/tests/agent_runtime_capabilities_contract.rs, docs/en/wegent/developer-guide/architecture.md, docs/zh/wegent/developer-guide/architecture.md
The executor drains only matching answered interactive forms. Contract tests verify that a later deferred form returns WaitingForUserInput. Documentation describes the matching rules.
Anthropic mock tool streaming
frontend/e2e/utils/mock-model-server.ts
The mock server emits configured Anthropic tool-use responses, serves multiple responses in order, validates offered tools, and resets serving counters.
ClaudeCode regression scenarios
frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts
End-to-end tests configure interactive skills and validate single and consecutive ClaudeCode clarification submissions across captured model requests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ClaudeCode
  participant Executor
  participant InteractiveMCP
  ClaudeCode->>Executor: Submit interactive-form answer
  Executor->>Executor: Match answered tool_use_id
  Executor->>InteractiveMCP: Forward later form with a different tool_use_id
  InteractiveMCP-->>Executor: Return deferred request
  Executor-->>ClaudeCode: WaitingForUserInput
Loading

Possibly related PRs

  • wecode-ai/Wegent#2272: Extends the same interactive MCP form flow and Claude deferred-form resume handling.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: correcting executor handling for deferred interactive-form requests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/claudecode-interactive-form-defer

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qdaxb
qdaxb marked this pull request as ready for review August 11, 2026 14:49

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
frontend/e2e/utils/mock-model-server.ts (1)

380-476: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the Anthropic SSE block serialization from writeAnthropicToolUseResponse.

This 98-line function handles validation, headers, message start, text blocks, tool blocks, and message completion. Extract focused helpers and reuse the shared message_start serialization with writeAnthropicStreamingResponse.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/e2e/utils/mock-model-server.ts` around lines 380 - 476, Refactor
writeAnthropicToolUseResponse into focused helpers for Anthropic SSE message
start, optional text content, tool-use content, and message completion. Reuse
the shared message_start serialization already used by
writeAnthropicStreamingResponse, preserving the current event order, indexes,
payloads, validation, headers, and response termination.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts`:
- Around line 761-790: Update the Skill Kind lookup request in the
skill-resolution flow to include the expected user_id, retain namespace=default,
and use exact_match=true. Replace the positional body.items?.[0] selection with
a search for the item whose name, namespace, and user_id match the requested
identity, then preserve the existing skillId validation and returned metadata
behavior.

---

Nitpick comments:
In `@frontend/e2e/utils/mock-model-server.ts`:
- Around line 380-476: Refactor writeAnthropicToolUseResponse into focused
helpers for Anthropic SSE message start, optional text content, tool-use
content, and message completion. Reuse the shared message_start serialization
already used by writeAnthropicStreamingResponse, preserving the current event
order, indexes, payloads, validation, headers, and response termination.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a58f45b1-1c8a-4e9e-90ed-70509cee5d92

📥 Commits

Reviewing files that changed from the base of the PR and between 3d71d88 and 27737b2.

📒 Files selected for processing (6)
  • docs/en/wegent/developer-guide/architecture.md
  • docs/zh/wegent/developer-guide/architecture.md
  • executor/src/process/mod.rs
  • executor/tests/agent_runtime_capabilities_contract.rs
  • frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts
  • frontend/e2e/utils/mock-model-server.ts

Comment on lines +761 to +790
const response = await request.get(
`${API_BASE_URL}/api/v1/kinds/skills?name=${encodeURIComponent(skillName)}&namespace=default&exact_match=false`,
{ headers: authHeaders() }
)
expect(response.status()).toBe(200)

const body = (await response.json()) as {
items?: Array<{
metadata?: {
namespace?: string
labels?: Record<string, string>
}
status?: {
fileHash?: string
}
}>
}
const skill = body.items?.[0]
const skillId = Number(skill?.metadata?.labels?.id)
expect(
skillId,
`Skill ${skillName} should expose a numeric metadata.labels.id`
).toBeGreaterThan(0)

const fileHash = skill?.status?.fileHash
return {
skill_id: skillId,
namespace: skill?.metadata?.namespace || 'default',
is_public: skill?.metadata?.labels?.user_id === '0',
content_hash: fileHash ? `sha256:${fileHash}` : undefined,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Query the Skill Kind with its full identity.

This request omits user_id, sets exact_match=false, and then selects body.items?.[0]. If another user owns a matching skill name, this test can attach the wrong skill metadata. Query with namespace, exact name, and the expected user_id. Then select the item that matches all three values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/e2e/tests/tasks/agent-conversation-regression.spec.ts` around lines
761 - 790, Update the Skill Kind lookup request in the skill-resolution flow to
include the expected user_id, retain namespace=default, and use
exact_match=true. Replace the positional body.items?.[0] selection with a search
for the item whose name, namespace, and user_id match the requested identity,
then preserve the existing skillId validation and returned metadata behavior.

Source: Coding guidelines

@qdaxb
qdaxb force-pushed the fix/claudecode-interactive-form-defer branch from 27737b2 to 79334ec Compare August 11, 2026 15:04
@qdaxb
qdaxb enabled auto-merge August 11, 2026 15:26
@qdaxb
qdaxb added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit c46e36d Aug 11, 2026
71 of 74 checks passed
@qdaxb
qdaxb deleted the fix/claudecode-interactive-form-defer branch August 11, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant