Skip to content

feat(query): add lifecycle identity and terminal reasons - #1682

Merged
kevincodex1 merged 10 commits into
Twigpine:mainfrom
chioarub:pr/query-lifecycle-identity-terminal-reasons
Jun 22, 2026
Merged

kevincodex1 merged 10 commits into
Twigpine:mainfrom
chioarub:pr/query-lifecycle-identity-terminal-reasons

Conversation

@chioarub

@chioarub chioarub commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add explicit query lifecycle identity, source, terminal reason, and timeout context to QueryGuard
  • track active API calls and tool uses with safe metadata for timeout/debug correlation
  • emit query lifecycle debug events for start, guard start, timeout, abort, and end paths

Validation

  • bun run typecheck
  • bun test src/utils/QueryGuard.test.ts
  • bun test tests/sdk/query-methods.test.ts tests/sdk/query-lifecycle.test.ts tests/sdk/query-concurrency.test.ts tests/sdk/query-happy-path.test.ts src/queryEngine.goal.test.ts src/query/autoCompactCooldown.test.ts src/query/stopHooks.goal.test.ts src/query/goalContinuation.test.ts src/query/providerMaxTokensCapRetry.test.ts src/query/toolFailureLoopGuard.test.ts
  • bun test src/services/tools/toolExecution.test.ts src/services/tools/toolHooks.test.ts
  • git diff --check

Summary by CodeRabbit

  • New Features

    • End-to-end query lifecycle tracking for active API calls and tool executions, including richer terminal reasons and safe active-operation snapshots.
    • Improved timeout and user-cancellation lifecycle reporting with more detailed debug context.
  • Refactor

    • Updated query guarding to expose current/previous lifecycle context and ensure lifecycle state is started, finalized, and cleaned up consistently.
    • Wired lifecycle tracking through tool execution and both streaming and fallback request paths.
  • Tests

    • Expanded QueryGuard and query-lifecycle tracker test coverage, with stricter snapshot-safety and richer timeout payload assertions.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces a query lifecycle tracking system. A new QueryLifecycleOperationTracker class and associated TypeScript types are added in src/utils/queryLifecycle.ts. QueryGuard is enriched with lifecycle context, terminal/abort reasons, and context getters. The tracker is wired through ToolUseContext, query.ts, toolExecution.ts, and REPL query start/end/cancel/timeout flows, with test coverage for all new behavior including Claude API lifecycle and tool execution lifecycle phases.

Changes

Query Lifecycle Tracking

Layer / File(s) Summary
Lifecycle types and OperationTracker
src/utils/queryLifecycle.ts
Defines QueryTerminalReason, active-operation shapes, context/guard/snapshot structures, and QueryLifecycleOperationTracker backed by Maps with start/update/end/clear/snapshot operations.
QueryGuard enrichment
src/utils/QueryGuard.ts
Adds internal context/lastContext fields, updates tryStart/end/forceEnd signatures with terminal and abort reasons, adds activeContext/lastContext getters, and reworks the watchdog to emit a QueryGuardTimeoutInfo payload before force-ending with 'query-timeout'.
API, query, and tool-execution tracker wiring
src/Tool.ts, src/query.ts, src/services/tools/toolExecution.ts, src/services/tools/toolExecution.test.ts
Adds optional queryLifecycle to ToolUseContext and forwards it through query.ts to callModel; starts and ends a tool-use lifecycle entry around checkPermissionsAndCallTool with Bash timeout metadata, replaying lifecycle starts when input is updated by hooks or permission decisions; tests verify lifecycle tracking during async validation and permission resolution phases.
REPL lifecycle orchestration
src/screens/REPL.tsx
Creates queryLifecycleTrackerRef, adds abort-label and operation-summary helpers, passes tracker through getToolUseContext and onQueryImpl, refactors tryStart to supply metadata and emit guard_start/start logs, reworks the finally block to derive terminalReason/abortReason and log lifecycle events, and updates onCancel/abortTimedOutQuery to snapshot and log abort_requested/abort_acknowledged with orphaned API-call warnings.
QueryGuard and Claude lifecycle tests
src/utils/QueryGuard.test.ts, src/services/api/claude.lifecycle.test.ts
Covers QueryGuard tryStart with query identity returning generation+context, timeout payload shape with active operations snapshot, end() terminal-reason stamping, metadata non-leakage across consecutive starts, and a full QueryLifecycleOperationTracker suite including snapshot safety constraints. New claude.lifecycle.test.ts validates tracker behavior for streaming and non-streaming fallback paths, including proper cleanup on success and error.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Gitlawb/openclaude#1030: Both PRs touch src/services/tools/toolExecution.ts, specifically the checkPermissionsAndCallTool function (main PR adds query-lifecycle start/end wiring there; retrieved PR makes an additional change in that function's error-handling path).
  • Gitlawb/openclaude#1623: Both PRs modify QueryGuard timeout handling and the REPL timeout callback to abort/terminate the active query execution when the watchdog fires, so the changes overlap at the same timeout plumbing points.

Suggested labels

enhancement

Suggested reviewers

  • jatmn
  • kevincodex1

🐰 A query's lifecycle now tracked from start to end,
With timeouts and cancels both marked and penned.
Operations recorded, snapshots so clean,
The finest lifecycle tracking you've seen! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a clear summary of changes and explains the rationale. However, it deviates from the template structure by using 'Validation' instead of the required 'Impact' and 'Testing' sections. Restructure the description to follow the template: add 'Impact' section with user-facing and developer/maintainer implications, rename 'Validation' to 'Testing' with checkboxes, and add 'Notes' section if applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(query): add lifecycle identity and terminal reasons' directly summarizes the main change: introducing explicit query lifecycle identity, source information, and terminal reason tracking to the QueryGuard component.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@chioarub
chioarub marked this pull request as ready for review June 16, 2026 23:50

@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: 3

🤖 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 `@src/screens/REPL.tsx`:
- Line 1485: The single queryLifecycleTrackerRef tracker is being injected into
all ToolUseContext instances around line 2593, but it should be scoped only to
the specific foreground query that owns it. Currently, multiple execution
contexts (background sessions, immediate commands, permission UI, agent resume,
compaction) share the same tracker, causing their operations to interfere when
the tracker is cleared at line 3065. Remove the tracker injection from the
general ToolUseContext creation and instead pass
queryLifecycleTrackerRef.current only in the specific code path where the
guarded foreground query context is constructed in onQueryImpl that belongs to
startResult.context. This ensures each query type has proper isolation of its
lifecycle operations.
- Around line 1771-1776: The warning log for orphaned API calls in the condition
checking timeout.activeOperations.apiCalls.length is premature because it fires
before the abort cleanup has actually run, causing normal timeout/cancel cases
to be incorrectly flagged as warnings. Instead of logging this as a 'warn' level
message about orphaned calls, change it to log at a non-warning level (such as
debug or info) with a diagnostic message that reflects these are active calls
during abort rather than truly orphaned calls, or defer this orphan detection
logic until after the query cleanup has actually completed.

In `@src/utils/QueryGuard.test.ts`:
- Around line 301-323: The test for snapshot security is redundant because the
string-based assertions on lines 320-322 check for absence of values that were
never provided to the startToolUse method call, so they don't actually validate
filtering behavior. Either remove the expect statements checking for '/home/',
'ANTHROPIC_API_KEY', and 'tool output' in the JSON stringified snapshot (since
the exact-keys assertion already validates the snapshot structure), or
restructure the test to pass sensitive data (like file paths or environment
variables) within the startToolUse parameters and verify they are actually
filtered out from the snapshot.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fbe5aef3-fa90-43fa-8a47-1a783c61e5ca

📥 Commits

Reviewing files that changed from the base of the PR and between 8f88608 and 067ea43.

📒 Files selected for processing (8)
  • src/Tool.ts
  • src/query.ts
  • src/screens/REPL.tsx
  • src/services/api/claude.ts
  • src/services/tools/toolExecution.ts
  • src/utils/QueryGuard.test.ts
  • src/utils/QueryGuard.ts
  • src/utils/queryLifecycle.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise in code

Files:

  • src/query.ts
  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/services/api/claude.ts
  • src/Tool.ts
  • src/services/tools/toolExecution.ts
  • src/utils/QueryGuard.ts
  • src/screens/REPL.tsx
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/query.ts
  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/services/api/claude.ts
  • src/Tool.ts
  • src/services/tools/toolExecution.ts
  • src/utils/QueryGuard.ts
  • src/screens/REPL.tsx
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/query.ts
  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/services/api/claude.ts
  • src/Tool.ts
  • src/services/tools/toolExecution.ts
  • src/utils/QueryGuard.ts
  • src/screens/REPL.tsx
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/QueryGuard.test.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/claude.ts
🔇 Additional comments (16)
src/utils/queryLifecycle.ts (2)

1-65: LGTM!


66-106: LGTM!

src/utils/QueryGuard.ts (6)

32-47: LGTM!


55-58: LGTM!


87-105: LGTM!


112-144: LGTM!


158-164: LGTM!

Also applies to: 195-242


248-270: LGTM!

src/utils/QueryGuard.test.ts (3)

73-82: LGTM!


86-235: LGTM!


257-299: LGTM!

src/Tool.ts (1)

63-63: LGTM!

Also applies to: 284-284

src/query.ts (1)

903-905: LGTM!

src/services/api/claude.ts (1)

173-173: LGTM!

Also applies to: 720-720, 1542-1542, 1855-1865, 1884-1888, 2863-2866

src/services/tools/toolExecution.ts (2)

1226-1236: LGTM!


1718-1718: LGTM!

Comment thread src/screens/REPL.tsx
Comment thread src/screens/REPL.tsx Outdated
Comment thread src/utils/QueryGuard.test.ts

@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: 2

🤖 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 `@src/utils/queryLifecycle.ts`:
- Around line 97-101: The updateApiCall method merges the update parameter
directly into the current object, which can propagate undefined values for
optional fields like startedAt, violating the type contract. Before merging
update with current on line 100, filter out any properties with undefined values
from the update object to ensure that only explicit, defined updates are
applied. This ensures that optional fields with number types like startedAt
cannot be accidentally overwritten with undefined during the spread operation.
- Around line 66-84: Add comment documentation above both toSafeApiCallSnapshot
and toSafeToolUseSnapshot functions to explain the purpose of the whitelisting
pattern. Document that these functions prevent accidental property leakage by
deliberately rebuilding the objects with only explicitly whitelisted properties
rather than spreading all properties from the input object, which protects
against unexpected properties being added at runtime.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 308f8444-3d98-4038-bbd0-64e075411bf0

📥 Commits

Reviewing files that changed from the base of the PR and between 067ea43 and 7e3327a.

📒 Files selected for processing (3)
  • src/screens/REPL.tsx
  • src/utils/QueryGuard.test.ts
  • src/utils/queryLifecycle.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with strict mode and ESM imports

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/screens/REPL.tsx
{src/services/**/*.ts,src/utils/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use execa for child processes

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
**/*.{ts,tsx,js,jsx,py,json,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow the existing code style in the touched files

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/screens/REPL.tsx
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/screens/REPL.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow TypeScript strict mode and type safety practices by running typecheck before submitting

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/screens/REPL.tsx
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/screens/REPL.tsx
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/utils/queryLifecycle.ts
  • src/utils/QueryGuard.test.ts
  • src/screens/REPL.tsx
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/utils/QueryGuard.test.ts
**/*.test.{ts,tsx,js}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Test the exact provider/model path you changed when possible

Files:

  • src/utils/QueryGuard.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/QueryGuard.test.ts
🔇 Additional comments (6)
src/utils/queryLifecycle.ts (1)

1-64: LGTM!

src/screens/REPL.tsx (3)

1485-1485: LGTM!


1771-1773: LGTM!

Also applies to: 2325-2327


2568-2589: LGTM!

Also applies to: 2852-2938, 3104-3104

src/utils/QueryGuard.test.ts (2)

86-108: LGTM!

Also applies to: 110-171, 203-215, 217-235, 256-299


301-346: Snapshot safety test now properly validates filtering behavior.

The updated test addresses the prior concern by passing sensitive data (prompt, apiKey, cwd, command, output) through type assertions (lines 303-323), then verifying those fields are excluded from snapshots via exact equality (lines 327-335), exact keys (lines 336-342), and string absence checks (lines 343-345). The type assertions intentionally bypass TypeScript's excess-property checking to simulate runtime scenarios where extra fields might be present, making the filtering verification meaningful.

Comment thread src/utils/queryLifecycle.ts
Comment thread src/utils/queryLifecycle.ts
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 17, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found one issue that needs to be addressed before this is ready.

Findings

  • [P3] Track tool uses before hook and permission waits
    src/services/tools/toolExecution.ts:876
    The lifecycle tracker only calls startToolUse() after schema validation, validateInput, all PreToolUse hooks, and resolveHookPermissionDecision() finish. If the query watchdog fires while a hook, classifier-backed permission decision, or interactive permission prompt is the thing blocking the turn, the timeout snapshot still reports activeToolUses=0, so the new lifecycle debug output loses the specific tool id/name it was added to correlate. Please start the safe tool-use tracking before those awaited pre-execution phases and end it on the existing early-return paths as well as the final tool execution path.

@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

🤖 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 `@src/services/tools/toolExecution.test.ts`:
- Around line 116-156: Add a new focused test case for Bash tool lifecycle
tracking. Create a test that uses BASH_TOOL_NAME instead of 'LifecycleTestTool'
when calling createToolFixture, and follow the same pattern as the existing test
that validates the snapshot during async input validation. In the new test, add
assertions to verify that the in-flight snapshot includes isBash: true and
timeoutMs properties in the captured toolUses array, ensuring the Bash-specific
lifecycle branch is exercised and properly tested.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 53802fad-25d2-4ac6-9908-7fcd732c6809

📥 Commits

Reviewing files that changed from the base of the PR and between 23673df and 0e9704e.

📒 Files selected for processing (2)
  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with strict mode and ESM imports

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
{src/commands/**/*.ts,src/services/**/*.ts,src/entrypoints/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use chalk for terminal color in CLI code

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
{src/services/**/*.ts,src/utils/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use execa for child processes

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
{src/integrations/**/*.ts,src/services/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Test the exact provider/model path you changed when possible for provider modifications

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
**/*.{ts,tsx,js,jsx,py,json,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow the existing code style in the touched files

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/services/tools/toolExecution.test.ts
**/*.test.{ts,tsx,js}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Test the exact provider/model path you changed when possible

Files:

  • src/services/tools/toolExecution.test.ts
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow TypeScript strict mode and type safety practices by running typecheck before submitting

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/tools/toolExecution.test.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
🔇 Additional comments (1)
src/services/tools/toolExecution.ts (1)

758-775: LGTM!

Also applies to: 1731-1733

Comment thread src/services/tools/toolExecution.test.ts
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 17, 2026
@chioarub
chioarub requested a review from jatmn June 17, 2026 18:45

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the update. I rechecked the previously discussed paths and found a couple of remaining issues.

Findings

  • [P3] Track API lifecycle per attempt/fallback request

    activeApiCallKey is started immediately before streaming .withResponse(), but it is only ended when the next streaming attempt begins or when queryModel() exits, and executeNonStreamingRequest() never starts its own lifecycle entry. That means two of the slow paths this PR is trying to diagnose report the wrong active operation: if withRetry() catches a retryable stream-creation error and sleeps for Retry-After/persistent retry, the failed request remains active through the backoff even though there is no network call; if streaming falls back to non-streaming, the snapshot either keeps showing the stale streaming request or shows no active non-streaming request at all. A query watchdog or user cancel during those windows will make api.call.active_on_abort point at the wrong phase of the hang. Please scope API lifecycle entries to each concrete request attempt, ending failed attempts before retry/backoff handling and starting/ending entries around each non-streaming fallback attempt as well.

  • [P3] Refresh Bash lifecycle metadata after hook/permission input rewrites

    The tool lifecycle entry is started from parsedInput.data before runPreToolUseHooks() and resolveHookPermissionDecision() can replace the input that will actually be executed. Those existing paths support updatedInput: passthrough hooks assign processedInput = result.updatedInput, hook allow/ask decisions pass hookPermissionResult.updatedInput, and PermissionRequest/SDK permission flows can also return updated input. For Bash, the new active-operation snapshot stores timeoutMs only once here, so a query hard-timeout or abort diagnostic can report the model-provided timeout even though a hook or permission handler raised/lowered the timeout for the command that is now waiting. That makes the new lifecycle debugging misleading exactly in the permission/hook wait and execution paths this PR is trying to illuminate. Please update the tracked tool-use metadata after the final processedInput is chosen, or delay the Bash timeout snapshot until after hook/permission resolution while still starting the operation early enough to cover the waits.

@chioarub
chioarub force-pushed the pr/query-lifecycle-identity-terminal-reasons branch 2 times, most recently from 1baf29d to 24ac83a Compare June 17, 2026 19:28

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/api/claude.ts (1)

2733-2750: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve provider routing and lifecycle source in the 404 fallback.

Line 2735 drops options.providerOverride, so provider-override requests that hit the 404 streaming fallback can retry non-streaming against the default client. The same call also omits querySource, so the new lifecycle snapshot records this fallback API call without its source.

Proposed fix
         // Fall back to non-streaming mode
         endActiveApiCall()
         const result = yield* executeNonStreamingRequest(
-          { model: options.model, source: options.querySource, effortValue: effort },
+          {
+            model: options.model,
+            source: options.querySource,
+            providerOverride: options.providerOverride,
+            effortValue: effort,
+          },
           {
             model: options.model,
             fallbackModel: options.fallbackModel,
             thinkingConfig,
             ...(isFastModeEnabled() && { fastMode: isFastMode }),
             signal,
+            querySource: options.querySource,
           },

As per coding guidelines, “Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny.”

🤖 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 `@src/services/api/claude.ts` around lines 2733 - 2750, The second parameter
object passed to executeNonStreamingRequest is missing two critical properties
that preserve the API routing context. Add providerOverride:
options.providerOverride to maintain provider-override routing when the 404
streaming fallback retries with non-streaming, and add querySource:
options.querySource to ensure the lifecycle snapshot captures the source of this
fallback API call. Update the options object in the executeNonStreamingRequest
call (the one containing model, fallbackModel, thinkingConfig, and signal) to
include both providerOverride and querySource properties from the options
parameter.

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 `@src/services/api/claude.lifecycle.test.ts`:
- Around line 54-81: The importFreshClaudeModule function uses global module
mocks via mock.module() which leak between concurrent test files and interfere
with src/services/api/client.test.ts. Replace the global mocking approach for
./client.js and ../vcr.js with local injection seams such as fetchOverride or
dependency injection parameters that only affect the current test scope. This
will isolate the test assertions so that mocks in claude.lifecycle.test.ts
cannot affect concurrent test files, preventing the smoke-and-tests check
failures caused by the fallback failed stub being invoked across multiple
unrelated client tests.

---

Outside diff comments:
In `@src/services/api/claude.ts`:
- Around line 2733-2750: The second parameter object passed to
executeNonStreamingRequest is missing two critical properties that preserve the
API routing context. Add providerOverride: options.providerOverride to maintain
provider-override routing when the 404 streaming fallback retries with
non-streaming, and add querySource: options.querySource to ensure the lifecycle
snapshot captures the source of this fallback API call. Update the options
object in the executeNonStreamingRequest call (the one containing model,
fallbackModel, thinkingConfig, and signal) to include both providerOverride and
querySource properties from the options parameter.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e6060392-3c7a-4d6b-b3d1-a501f5ea856e

📥 Commits

Reviewing files that changed from the base of the PR and between 0a454ae and 1baf29d.

📒 Files selected for processing (4)
  • src/services/api/claude.lifecycle.test.ts
  • src/services/api/claude.ts
  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (13)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with strict mode and ESM imports

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
{src/commands/**/*.ts,src/services/**/*.ts,src/entrypoints/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use chalk for terminal color in CLI code

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
{src/services/**/*.ts,src/utils/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use execa for child processes

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
{src/integrations/**/*.ts,src/services/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Test the exact provider/model path you changed when possible for provider modifications

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
**/*.{ts,tsx,js,jsx,py,json,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow the existing code style in the touched files

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
**/*.test.{ts,tsx,js}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Test the exact provider/model path you changed when possible

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow TypeScript strict mode and type safety practices by running typecheck before submitting

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
**

⚙️ CodeRabbit configuration file

**: # AGENTS.md - AI Agent Coding Guide

This guide is for AI coding agents working in the OpenClaude repository. Read it before changing code, and also follow CONTRIBUTING.md for contributor policy, PR expectations, review follow-up, and project scope.

Project Snapshot

OpenClaude is a coding-agent CLI for cloud and local model providers. It supports OpenAI-compatible APIs, Anthropic, Gemini, DeepSeek, Ollama, MCP, local backends, slash commands, tools, agents, and a React/Ink terminal UI.

The installed CLI runs on Node.js >=22.0.0. Bun is used for source builds, scripts, dependency management, and tests.

Work Style

  • Keep changes focused on one problem.
  • Prefer existing patterns in the file or nearby module.
  • Avoid unrelated formatting, renames, dependency changes, or broad rewrites.
  • Add or update tests when behavior changes.
  • Update docs when setup, commands, provider behavior, or user-facing behavior changes.
  • For new features, larger refactors, dependencies, or runtime changes, follow the issue-first guidance in CONTRIBUTING.md.

Stack And Conventions

  • TypeScript with strict mode and ESM imports.
  • React + Ink for terminal UI.
  • Bun lockfile and Bun scripts for development workflows.
  • Node runtime for the built CLI.
  • Python exists for legacy/local-provider helper code. Do not add new Python code or expand Python-based features unless a maintainer explicitly approves that direction.

Common libraries and patterns:

  • chalk for terminal color.
  • commander for CLI argument parsing.
  • execa for child processes.
  • Existing service, provider, settings, permission, and UI patterns over new abstractions.

Repository Map

  • src/commands/ - slash and CLI command implementations.
  • src/components/ - React/Ink UI components.
  • src/services/ - API, MCP, OAuth, wiki, voice, and other service integrations.
  • src/tools/ - tool implementations.
  • src/utils/ - shared utilities.
  • `src/integration...

Files:

  • src/services/tools/toolExecution.test.ts
  • src/services/api/claude.lifecycle.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/claude.lifecycle.test.ts
  • src/services/api/claude.ts
🪛 GitHub Check: smoke-and-tests
src/services/api/claude.lifecycle.test.ts

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:744:30)

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:687:30)

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:606:47)

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:472:30)

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:420:30)

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:364:47)

[failure] 26-26: error: 400 fallback failed

  at makeApiError (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:26:10)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/claude.lifecycle.test.ts:243:15)
  at <anonymous> (/home/runner/work/openclaude/openclaude/src/services/api/client.test.ts:298:47)
🔇 Additional comments (3)
src/services/api/claude.ts (1)

688-721: LGTM!

Also applies to: 832-924, 1557-1569, 1880-1915, 2632-2651, 2891-2893

src/services/tools/toolExecution.ts (1)

758-784: LGTM!

Also applies to: 938-943, 1019-1030, 1210-1215, 1744-1745

src/services/tools/toolExecution.test.ts (1)

256-312: LGTM!

Comment thread src/services/api/claude.lifecycle.test.ts Outdated
@chioarub
chioarub force-pushed the pr/query-lifecycle-identity-terminal-reasons branch from 24ac83a to 0d2019c Compare June 17, 2026 19:39

@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 (2)
src/services/api/claude.lifecycle.test.ts (2)

99-106: ⚡ Quick win

Consider adding error handling to prevent test hangs.

The drainGenerator helper uses an infinite loop without error handling. If the generator throws or never completes, the test could hang indefinitely. Consider wrapping the await in a try-catch to provide better error messages.

♻️ Proposed enhancement
 async function drainGenerator<T>(
   generator: AsyncGenerator<unknown, T>,
 ): Promise<T> {
   while (true) {
-    const result = await generator.next()
+    try {
+      const result = await generator.next()
-    if (result.done) return result.value
+      if (result.done) return result.value
+    } catch (error) {
+      // Clean up generator on error
+      await generator.return(undefined).catch(() => {})
+      throw error
+    }
   }
 }
🤖 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 `@src/services/api/claude.lifecycle.test.ts` around lines 99 - 106, The
drainGenerator function lacks error handling and could cause test hangs if the
generator throws an error or fails to complete. Wrap the await generator.next()
call inside a try-catch block in the drainGenerator function to catch and handle
any errors thrown by the generator, ensuring the test fails with a clear error
message rather than hanging indefinitely.

108-114: 💤 Low value

Type assertion in test helper could hide incompleteness.

The makeParams function uses a type assertion on line 113 that forces the minimal test object into BetaMessageStreamParams. While acceptable for test fixtures, this may hide missing required fields if the type definition changes.

🤖 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 `@src/services/api/claude.lifecycle.test.ts` around lines 108 - 114, Remove the
type assertion on the return object in the makeParams function and instead
explicitly define all required fields from the BetaMessageStreamParams type
definition. Check what fields are required by BetaMessageStreamParams and add
them to the returned object rather than forcing it with the as keyword. This
ensures that if BetaMessageStreamParams changes in the future, the test helper
will catch any missing required fields at compile time rather than hiding them
with the assertion.
🤖 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 `@src/services/api/claude.lifecycle.test.ts`:
- Around line 227-265: The double type cast on makeBetaMessage() as unknown as
Record<string, unknown> when calling makeJsonResponse indicates a type mismatch
and hides potential type errors. Modify the makeJsonResponse function signature
to accept unknown as its parameter type instead of Record<string, unknown>, then
update the call in the test to pass makeBetaMessage() directly without any type
assertions. Since JSON.stringify can handle any type, this change will allow the
function to be more flexible while removing the unnecessary intermediate cast.

---

Nitpick comments:
In `@src/services/api/claude.lifecycle.test.ts`:
- Around line 99-106: The drainGenerator function lacks error handling and could
cause test hangs if the generator throws an error or fails to complete. Wrap the
await generator.next() call inside a try-catch block in the drainGenerator
function to catch and handle any errors thrown by the generator, ensuring the
test fails with a clear error message rather than hanging indefinitely.
- Around line 108-114: Remove the type assertion on the return object in the
makeParams function and instead explicitly define all required fields from the
BetaMessageStreamParams type definition. Check what fields are required by
BetaMessageStreamParams and add them to the returned object rather than forcing
it with the as keyword. This ensures that if BetaMessageStreamParams changes in
the future, the test helper will catch any missing required fields at compile
time rather than hiding them with the assertion.
🪄 Autofix (Beta)

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: 191d9f0e-2ca6-4fab-b407-e3ae10b1f815

📥 Commits

Reviewing files that changed from the base of the PR and between 1baf29d and 24ac83a.

📒 Files selected for processing (4)
  • src/services/api/claude.lifecycle.test.ts
  • src/services/api/claude.ts
  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/services/tools/toolExecution.test.ts
  • src/services/tools/toolExecution.ts
  • src/services/api/claude.ts

Comment thread src/services/api/claude.lifecycle.test.ts
@chioarub
chioarub force-pushed the pr/query-lifecycle-identity-terminal-reasons branch from 0d2019c to b5288a5 Compare June 17, 2026 19:45
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 17, 2026
@chioarub
chioarub requested a review from jatmn June 17, 2026 19:47
jatmn
jatmn previously approved these changes Jun 17, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the contribution. I do not see any actionable issues from my review.

@kevincodex1 LGTM

@kevincodex1

Copy link
Copy Markdown
Member

kindly rebase and fix confclits

@chioarub
chioarub dismissed stale reviews from jatmn and coderabbitai[bot] via 5c52544 June 18, 2026 06:09

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the update. I took another skeptical pass over the changed paths, prior reviewer threads, and neighboring query/tool/subagent flows. I still found one issue that needs to be addressed:

Findings

  • [P2] Preserve lifecycle tracking for foreground subagent calls
    src/utils/forkedAgent.ts:381
    The foreground REPL now only attaches queryLifecycle when onQueryImpl builds the guarded context, and query.ts only forwards toolUseContext.queryLifecycle into callModel. However, when an Agent tool launches a synchronous foreground subagent, createSubagentContext() rebuilds the child context without copying that field, so the child query loop runs its API calls and nested tool uses with no lifecycle tracker or child identity. The parent Agent tool also does not get a QueryGuard lease because createToolQueryLeaseInput() only leases Bash/PowerShell tools, so a timeout/cancel during a hung subagent API request reports no active child API call even though this PR is adding lifecycle identity and active-operation snapshots for exactly that debugging path. Please carry an appropriate lifecycle tracker into foreground child contexts, or create an explicit child tracker/parent linkage so subagent API/tool activity is visible in timeout and cancel diagnostics without reintroducing tracking for unrelated background contexts.

@chioarub
chioarub requested a review from jatmn June 18, 2026 19:04

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Findings

  • [P2] Emit timeout query.end only after abort cleanup is acknowledged
    src/screens/REPL.tsx:1770
    On the timeout path, abortTimedOutQuery() logs query.end immediately after calling abort('query-timeout'), before the queued abort_acknowledged callback runs and before QueryGuard._handleTimeout() reaches its finally block and calls forceEnd(). That means the new lifecycle log can report an end event while activeApiCalls/activeToolUses are still nonzero and before the abort has actually unwound, producing an event order like timeout -> abort_requested -> end -> abort_acknowledged. For the lifecycle diagnostics this PR adds, end should be the terminal/cleanup point, not a pre-cleanup snapshot. Please move the timeout query.end emission to the acknowledged/post-force-end side, or use a different event name for the pre-cleanup active-operation snapshot so parsers and humans do not treat the timed-out query as completed before cleanup has run.

  • [P2] Clear discarded streaming-tool lifecycle entries before fallback continues
    src/query.ts:954
    When streaming fallback occurs after streaming tool execution has already started a tool, this path discards the old StreamingToolExecutor and immediately creates a replacement with the same toolUseContext.queryLifecycle. However StreamingToolExecutor.discard() only sets discarded = true; it does not abort in-flight runToolUse() calls or end their queryLifecycle.startToolUse() entries. Those abandoned tools keep appearing in the shared tracker until the underlying tool eventually exits, so the fallback request's timeout/cancel snapshots can include active tool uses from the discarded streaming attempt, and long-running Bash tools can make the new lifecycle diagnostics point at the wrong work. Please either end/clear lifecycle entries for discarded tools or abort the discarded executor's in-flight tools before continuing with the fallback executor.

@chioarub
chioarub requested a review from jatmn June 18, 2026 20:34

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the update. I found one issue that still needs to be addressed.

Findings

  • [P2] Complete the timeout cleanup request before emitting query.end
    src/screens/REPL.tsx:1776
    The latest timeout path queues abort_acknowledged and query.end in a microtask immediately after abort('query-timeout'), but that microtask is not tied to the model/tool cleanup path. QueryGuard invokes the timeout handler before forceEnd(), and API lifecycle cleanup still happens later in the aborted query generator's finally block, so a timed-out request can still emit query.end while queryLifecycleTrackerRef.current.snapshot() contains active API calls or tool uses. Please complete the prior cleanup request by moving the terminal query.end emission to the actual post-cleanup path, or log this microtask snapshot as a non-terminal pre-cleanup event instead.

@chioarub

Copy link
Copy Markdown
Contributor Author

Addressed the latest timeout cleanup finding in 72d88a5.

What changed:

  • The timeout handler no longer emits terminal query.end; it only logs timeout/abort acknowledgement and performs existing UI cleanup.
  • Terminal query.end is emitted from the query finally cleanup path, including timed-out generations completed by QueryGuard.forceEnd(), using the completed guard context for the same generation.
  • Added regression coverage that asserts the timeout handler cannot emit query.end and that timeout completion is logged from the cleanup path.

Verification:

  • bun test src/screens/REPL.queryLifecycle.test.ts
  • bun test src/screens/REPL.queryLifecycle.test.ts src/services/tools/StreamingToolExecutor.test.ts src/services/tools/toolExecution.test.ts src/utils/queryLifecycle.test.ts src/utils/QueryGuard.test.ts src/services/api/claude.lifecycle.test.ts src/screens/replFallbackModelProp.test.ts src/services/tools/queryActivityLease.test.ts
  • git diff --check
  • bun run typecheck
  • bun run typecheck:type-tests
  • bun run smoke

Remote checks on the current head are green: CodeRabbit, smoke-and-tests, typecheck, and web. There are no unresolved current review threads.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the update. I rechecked the previously discussed paths and do not see any remaining actionable issues from my side.

@kevincodex1 LGTM

@kevincodex1 kevincodex1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@kevincodex1
kevincodex1 merged commit 23bc49a into Twigpine:main Jun 22, 2026
4 checks passed
Gravirei pushed a commit to Gravirei/openclaude that referenced this pull request Jun 22, 2026
* feat(query): add lifecycle identity and terminal reasons

* fix(query): isolate lifecycle tracking context

* fix(query): guard lifecycle metadata updates

* fix(query): track lifecycle during tool waits

* test(query): cover bash lifecycle metadata

* fix(query): scope lifecycle tracking to request attempts

* fix(query): disambiguate lifecycle abort log reason

* fix(query): preserve foreground subagent lifecycle tracking

* fix(query): clean up timeout and fallback lifecycle events

* fix(query): emit timeout end after cleanup
@chioarub
chioarub deleted the pr/query-lifecycle-identity-terminal-reasons branch June 22, 2026 05:54
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
Port provider-agnostic timeout abort mechanism to OpenCC. The
upstream `[codex]` tag is misleading — the change hooks QueryGuard's
timeout to abort in-flight work, which OpenCC needs as substrate for
the Twigpine#1682 lifecycle port. Codex-specific paths are excluded per
provider policy.

Upstream SHA: 174ebd5
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
Port activity-aware leases to OpenCC. Required substrate for the
Twigpine#1682 lifecycle subsystem port (QueryGuard wiring depends on the
lease / activity / timeout-handler surface added here).

Upstream SHA: 23cfc24
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
…for Twigpine#1682 lifecycle port)

# Conflicts:
#	src/utils/QueryGuard.test.ts
#	src/utils/QueryGuard.ts
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
Port the type module + tracker from Twigpine#1682 to OpenCC. Zero callers yet;
later commits in this 4-part chain will wire it into QueryGuard,
context types, and the streaming executor.

Upstream SHA: 23bc49a (commit 1 of 4, types-only slice)
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
Port the lifecycle-aware delta from Twigpine#1682 on top of the modernized
QueryGuard (substrate Twigpine#1686 already merged). Adds tryStart(metadata) /
end(gen, terminalReason) / forceEnd(reason, abort) / activeContext /
lastContext. Preserves setTimeoutHandler(generation, reason) API.

Upstream SHA: 23bc49a (commit 2 of 4, QueryGuard slice)
Prereq: 1e57836c (commit 1 of 4) + 5b05ced (substrate Twigpine#1686)
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jul 4, 2026
…f 4)

Port the 5-file context-types delta from Twigpine#1682 to OpenCC. Adds
queryLifecycle to ToolUseContext, instantiates the tracker in
MainLoopContext, plumbs through forkedAgent / runAgent / REPL.

Upstream SHA: 23bc49a (commit 3 of 4, context-types slice)
Prereq: 73e2101 (commit 2 of 4) + 5b05ced (substrate Twigpine#1686) + 1e57836c (commit 1)
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.

3 participants