Skip to content

feat(signals): implement execution signals extraction (P4)#2

Merged
DataDave-Dev merged 3 commits into
DataDave-Dev:mainfrom
YasserYG8:feat/p4-execution-signals
Jul 11, 2026
Merged

feat(signals): implement execution signals extraction (P4)#2
DataDave-Dev merged 3 commits into
DataDave-Dev:mainfrom
YasserYG8:feat/p4-execution-signals

Conversation

@YasserYG8

@YasserYG8 YasserYG8 commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR implements P4: Execution Signals as outlined in the Modlane roadmap. It adds a parser that analyzes the conversation history of incoming agent requests (OpenAIBody and AnthropicBody) to extract key session metrics and heuristics. These signals are necessary to support classification-first routing (P5) and error-aware escalation (P6).

What Was Added/Changed

  1. Extended Request Context:
    • Modified the neutral ChatRequest interface in src/providers/types.ts to retain dialect ("openai" | "anthropic") and the original rawBody payload.
    • Modified src/server.ts to assign these properties in the gateway during parsing.
  2. Signals Core Extractor (src/signals.ts):
    • Implemented extractSignals(req) to parse OpenAI and Anthropic formats.
    • Extracts statistics (message count, character size) and compiles tool calls and tool results history.
    • Computes heuristics:
      • Files Touched: Case-insensitively parses tool call arguments for path parameters.
      • Repeated Edits: Checks if consecutive edits were targetted at the same file path.
      • Test/Build Failures: Scans result strings for error keywords (e.g. FAIL, compile error, exit status).
      • Consecutive Failures: Counts sequential failing actions to detect stuck states.
  3. Spec-first Documentation:
    • Added proposal.md and tasks.md under openspec/changes/P4-execution-signals/.

Testing

Added comprehensive unit tests in src/signals.test.ts verifying extraction accuracy under both OpenAI and Anthropic dialects.

Verified that:

  • pnpm run typecheck passes with zero compiler errors.
  • pnpm run build succeeds.
  • pnpm test runs and passes all 22 tests (including 4 new signals tests).

Summary by CodeRabbit

  • New Features
    • Added execution signal extraction for requests, including message/character totals, tool call/result activity, detected failures, touched file paths, repeated edits, and consecutive failure counts.
    • Added support for both OpenAI- and Anthropic-formatted request histories.
    • Requests now retain their source format and original body data for analysis.
  • Tests
    • Added unit tests covering signal extraction across both dialects, including error detection, file parsing, repeated edits, consecutive failures, and benign “fail” text handling.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@DataDave-Dev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b8690d0c-7b0d-433f-a4ab-ab68c870b5af

📥 Commits

Reviewing files that changed from the base of the PR and between b5126ac and 1e6c246.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml
📝 Walkthrough

Walkthrough

Adds request metadata capture and a new extractSignals module that parses OpenAI and Anthropic tool activity into execution, file-edit, and failure signals, with Vitest coverage and OpenSpec task documentation.

Changes

Execution Signals

Layer / File(s) Summary
Request context capture
src/providers/types.ts, src/server.ts
ChatRequest retains optional dialect and rawBody fields, which handleChat populates from inbound requests.
Signal extraction
src/signals.ts
Adds signal types and dialect-specific parsing for tool calls and results, including touched files, repeated edits, and failure counters.
Validation and specification
src/signals.test.ts, openspec/changes/P4-execution-signals/*
Tests OpenAI and Anthropic extraction, consecutive failures, benign failure text, and edit detection; documents completed P4 tasks and implementation status.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant handleChat
  participant extractSignals
  participant ToolResults
  Client->>handleChat: Send dialect and request body
  handleChat->>extractSignals: Pass ChatRequest with rawBody
  extractSignals->>ToolResults: Parse tool calls and results
  ToolResults-->>extractSignals: Return execution and failure data
  extractSignals-->>Client: Provide derived execution signals
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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: adding execution signals extraction for P4.
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
🧪 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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/signals.ts`:
- Around line 144-154: Guard the `tc.name` access in the signal-processing loop
before invoking `.toLowerCase()`. For undefined or otherwise missing tool names,
skip the edit-tool classification while preserving file-path extraction and
filesTouched updates; only call `.toLowerCase()` when a valid name is present.
🪄 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: d8da5dbe-09a1-4025-813f-9a4199c2c0bb

📥 Commits

Reviewing files that changed from the base of the PR and between 8d9ecac and 1ac558a.

📒 Files selected for processing (6)
  • openspec/changes/P4-execution-signals/proposal.md
  • openspec/changes/P4-execution-signals/tasks.md
  • src/providers/types.ts
  • src/server.ts
  • src/signals.test.ts
  • src/signals.ts

Comment thread src/signals.ts
Comment on lines +144 to +154
for (const tc of signals.toolCalls) {
const path = extractFilePath(tc.arguments);
if (path) {
if (!signals.filesTouched.includes(path)) {
signals.filesTouched.push(path);
}
const lowerName = tc.name.toLowerCase();
if (editTools.some((t) => lowerName.includes(t))) {
fileEdits.push(path);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard against undefined tc.name before calling .toLowerCase().

Tool call names are pushed from raw.body without validation (line 91: tc.function.name, line 115: part.name). If either is undefined in a malformed request, tc.name.toLowerCase() on line 150 throws a TypeError. Since rawBody is user-controlled input, this is a reachable crash path.

🛡️ Proposed fix
   for (const tc of signals.toolCalls) {
     const path = extractFilePath(tc.arguments);
     if (path) {
       if (!signals.filesTouched.includes(path)) {
         signals.filesTouched.push(path);
       }
-      const lowerName = tc.name.toLowerCase();
+      const lowerName = (tc.name ?? "").toLowerCase();
       if (editTools.some((t) => lowerName.includes(t))) {
         fileEdits.push(path);
       }
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const tc of signals.toolCalls) {
const path = extractFilePath(tc.arguments);
if (path) {
if (!signals.filesTouched.includes(path)) {
signals.filesTouched.push(path);
}
const lowerName = tc.name.toLowerCase();
if (editTools.some((t) => lowerName.includes(t))) {
fileEdits.push(path);
}
}
for (const tc of signals.toolCalls) {
const path = extractFilePath(tc.arguments);
if (path) {
if (!signals.filesTouched.includes(path)) {
signals.filesTouched.push(path);
}
const lowerName = (tc.name ?? "").toLowerCase();
if (editTools.some((t) => lowerName.includes(t))) {
fileEdits.push(path);
}
}
🤖 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/signals.ts` around lines 144 - 154, Guard the `tc.name` access in the
signal-processing loop before invoking `.toLowerCase()`. For undefined or
otherwise missing tool names, skip the edit-tool classification while preserving
file-path extraction and filesTouched updates; only call `.toLowerCase()` when a
valid name is present.

@YasserYG8 YasserYG8 requested a review from DataDave-Dev July 11, 2026 13:11
Substring includes("fail") flagged benign tokens like "failover" and
"failsafe" as failures. Switch to word-boundary regex and add a
regression test.
pnpm@11.10.0 dropped Node 20 support (needs node:sqlite), breaking the
build job at setup. Bump the CI runner to Node 22.
@DataDave-Dev DataDave-Dev merged commit 7eb631d into DataDave-Dev:main Jul 11, 2026
2 checks passed
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.

2 participants