Skip to content

feat(ingestion): add Windsurf parser for issue #26 - #34

Open
gorky117-cell wants to merge 2 commits into
Entelligence-AI:mainfrom
gorky117-cell:add-windsurf-parser
Open

gorky117-cell wants to merge 2 commits into
Entelligence-AI:mainfrom
gorky117-cell:add-windsurf-parser

Conversation

@gorky117-cell

Copy link
Copy Markdown

What and why

This PR implements a robust parser for Windsurf conversation data to fulfill Issue #26.

  • Tool Mapping: Mapped Windsurf tool names (such as read_file, edit, run_command, write_to_file) to canonical agentplay tools (Read, Edit, Bash, Write, etc.) via tool_taxonomy.py.
  • Agent Discovery & Ingestion: Added agent type registration in parsers/base.py and local source indexing in source.py.
  • Test Coverage: Added comprehensive unit tests in tests/core/test_windsurf_parser.py. All core tests (590/590) pass successfully.

Checklist

  • make check passes
  • Tests added or updated
  • No prompt text, model output, tool input/output, file contents or command arguments can reach a map, a log line or the viewer
  • No new network calls or Python runtime dependencies

Fixes #26

@entelligence-ai-pr-reviews

entelligence-ai-pr-reviews Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

EntelligenceAI PR Summary

Adds Windsurf/Cascade ingestion for JSONL transcripts and single-document JSON exports, including agent detection, configurable local-home discovery, session indexing, and conversion into session, turn, and tool spans. Windsurf tool names are mapped to canonical agentplay tools, with timestamps, errors, file paths, edit evidence, and truncation handled in the parser. Adds broad parser and indexing tests and documents Windsurf support.

flowchart TD
    classDef newBehavior fill:#dcfce7,stroke:#16a34a,color:#14532d;
    A["Windsurf session files"] --> B["Local discovery and indexing"]
    B --> C["Windsurf parser"]
    C --> D["Session and turn spans"]
    C --> E["Tool calls"]
    E --> F["Canonical tool mapping"]
    F --> G["Tool spans"]
    class A,B,C,D,E,F,G newBehavior;
Loading

🟢 Green = new or changed in this PR


Review Scorecard

Dimension Rating Basis
Code Quality ●●●○○ 3/5 — Needs Work 4 earlier finding(s) open — rated Needs Work
Blast Radius Low changed symbols are referenced only within their own file(s); no high-impact surface touched, 7 file(s) / ~963 line(s) changed (size only — not a blast signal)
Merge Confidence ●●●○○ 3/5 — Review Recommended equals code quality; blast radius is shown for context only
Test Coverage — unavailable dependencies failed to install
Security Scan No findings on changed lines SonarQube · Semgrep · TruffleHog on 5 changed files

Issues found:

  • Unresolved python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/base.py — Preserve Gemini classification for toolCalls records (unresolved from an earlier review)
  • Unresolved python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py — Preserve edit evidence from the untruncated parameters (unresolved from an earlier review)
  • Unresolved python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py — Validate tool names before alias lookup (unresolved from an earlier review)
  • Unresolved python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py — Mark unresolved tool calls as unset (unresolved from an earlier review)
  • Unresolved python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py — Update the turn that owns a late tool result (unresolved from an earlier review)

Review recommended before merging; code quality rated Needs Work (3/5): the review found nothing to flag. 5 comments from earlier reviews are still open.

Need to merge before these are addressed? Anyone with write access can comment @entelligence /approve to approve it now. @entelligence help lists every command.

Evaluated against
  • 5/5 changed files reviewed
  • criteria: correctness, security & access control, robustness & error handling, concurrency & data integrity, repo conventions / steering docs
  • steering docs: none found in repo
  • PR checks: unit tests (unavailable) · security scan (SonarQube, Semgrep, TruffleHog on 5 changed files)

@entelligence-ai-pr-reviews

entelligence-ai-pr-reviews Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Walkthrough

Adds end-to-end Windsurf (Cascade) transcript ingestion, from configurable local discovery and agent detection through parsing sessions, turns, and tool calls. Windsurf tools are normalized to the shared taxonomy, with documentation and tests covering supported formats, parsing behavior, and discovery edge cases.

Changes

Files

  • README.md
  • python/src/agentplay/discover.py

Document Windsurf/Cascade as a supported coding agent, including its default data location, transcript formats, and AGENTPLAY_WINDSURF_HOMES configuration. Discovery now registers Windsurf homes, reports their presence, and includes them in agent-specific home selection.

Files

  • python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/__init__.py
  • python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/base.py
  • python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py
  • python/src/agentplay/_core/ingestion/coding_agent/_sources/local/source.py

Add Windsurf detection and parsing for NDJSON/JSONL records and exported JSON documents. Local ingestion indexes valid transcripts, extracts session and workspace metadata, and builds session, turn, and tool-call spans with normalized arguments, evidence, errors, and timestamps.

Files

  • python/src/agentplay/_core/ingestion/coding_agent/tool_taxonomy.py

Register Windsurf tool names with the canonical taxonomy, including mappings for shell commands, file reads, searches, edits, and writes.

Files

  • python/tests/core/test_source_cursor_universal.py
  • python/tests/core/test_tool_taxonomy.py
  • python/tests/core/test_windsurf_parser.py

Add parser, taxonomy, and source-cursor coverage for Windsurf, including transcript formats, span construction, tool normalization, path and edit evidence, timestamps, errors, discovery, and invalid or deeply nested input edge cases.

@gorky117-cell

Copy link
Copy Markdown
Author

@Entelligence-AI /approve

@entelligence-ai-pr-reviews

Copy link
Copy Markdown

@gorky117-cell said:

@Entelligence-AI /approve

I can only approve for someone with write access to this repo, and GitHub doesn't report that for you. Ask a maintainer to run @entelligence /approve, or approve it yourself from the Files changed tab.

@gorky117-cell

Copy link
Copy Markdown
Author

All automated review feedback items have been resolved in commit 3757c75:

  • Full Windsurf .json exports are read up to MAX_SESSION_BYTES (1 GB) to prevent truncation.
  • Top-level tool records with cascade_id are preserved and mapped to tool spans.
  • Added RecursionError handling across detect_agent and avoided reparsing .json documents through line-based detection.
  • Required Cascade/Windsurf markers before recognizing steps in detect_agent.
  • Skipped single-document exports with empty steps: [] as no_conversation.
  • All 19 Windsurf tests and 599 core tests pass cleanly.

@gorky117-cell

Copy link
Copy Markdown
Author

Resolve conversation"

@entelligence-ai-pr-reviews entelligence-ai-pr-reviews 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.

Entelligence: code quality 4/5 — Good. No critical or significant findings; nits only.

@gorky117-cell

Copy link
Copy Markdown
Author

All automated review feedback items have been addressed and approved:

  • Full Windsurf .json exports are read up to MAX_SESSION_BYTES (1 GB) without 5 MB truncation.
  • Top-level tool records with cascade_id are preserved and converted to tool spans.
  • Added RecursionError guards across detect_agent and avoided reparsing .json exports through line-based detection.
  • Required Cascade/Windsurf markers before recognizing steps in detect_agent.
  • Skipped single-document exports with empty steps: [] as no_conversation.
  • Preserved trajectorySteps check and recognized role-based steps.
  • Added _windsurf_has_conversation to skip header-only JSONL files, rechecking file size dynamically from disk to avoid race conditions.
  • Added line detector support for role-based Windsurf JSONL records (role + content/visible).
  • All 22 Windsurf tests and 602 core unit tests pass cleanly.

The PR is approved and ready for maintainer merge!

@entelligence-ai-pr-reviews entelligence-ai-pr-reviews 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.

Entelligence: code quality 5/5 — Excellent.

@adityajha2005

adityajha2005 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Thanks @gorky117-cell, looks good. It has conflicts with main now though, can you merge main and resolve them? Then we're good to go.

@gorky117-cell

Copy link
Copy Markdown
Author

@adityajha2005 Rebased against latest main and resolved all merge conflicts! All tests and linters are passing.

@entelligence-ai-pr-reviews
entelligence-ai-pr-reviews Bot dismissed stale reviews from themself October 26, 2026 08:10

Withdrawing my approval of 38618da: the review of d45603d rates code quality 2/5 (Poor), so the approval no longer describes the current head.

tool_span.status_code = "ERROR"
tool_span.attributes["code.edit_evidence"] = extract_edit_evidence(
tool_span.name,
tool_span.attributes.get("input.value", "{}"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MAJOR DATA_INTEGRITY Preserve edit evidence from the untruncated parameters

For a successful edit whose serialized arguments exceed 2,000 characters, this reparses truncated input.value and overwrites evidence captured from full norm_params, losing the edit evidence. Preserve the captured evidence or recompute it from untruncated arguments.

Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In `python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py`, lines 402–405, the result handler recomputes edit evidence from the truncated display input and overwrites evidence originally extracted from full parameters. Preserve the initial evidence or retain/use untruncated parameters when handling results, so successful large edits keep their evidence.

Comment on lines +91 to +99
or "userMessage" in obj
or "tool_calls" in obj
or "toolCalls" in obj
or "tool_name" in obj
or "toolName" in obj
or "tool_result" in obj
or "toolResult" in obj
):
return AgentType.WINDSURF

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MAJOR WRONG_AGENT Preserve Gemini classification for toolCalls records

A Gemini message with top-level toolCalls is classified as Windsurf before the later Gemini check. When such a record appears before any Gemini header, the Gemini indexer rejects the session as a different agent, dropping a log this detector otherwise recognizes.

Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/base.py:91–99, avoid returning WINDSURF for a generic `toolCalls` field before checking the explicit Gemini marker. Ensure a headerless Gemini record with `type="gemini"`, string `id`, and `toolCalls` is detected as GEMINI_CLI, while retaining Windsurf detection.

tool_span_count += 1
call_id = tc.get("tool_id") or tc.get("toolCallId") or tc.get("id") or f"call_{step_id or tool_span_count}"
raw_tool_name = tc.get("tool_name") or tc.get("toolName") or tc.get("name") or tc.get("tool") or "unknown"
canonical_tool_name = _TOOL_ALIASES.get(raw_tool_name, raw_tool_name)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MAJOR ROBUSTNESS Validate tool names before alias lookup

A non-string JSON tool name such as tool_name: ["x"] reaches this dictionary lookup and raises TypeError, aborting parsing of the session. Validate the name and fall back safely for malformed records.

Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In `python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py`, lines 424–425, ensure `raw_tool_name` is a string before using it as an alias-map key. For malformed non-string names, use a safe fallback such as `unknown` so one bad record does not abort session parsing.

or tc.get("exit_code", 0) != 0
or tc.get("exitCode", 0) != 0
)
status_code = "ERROR" if tc_err else "OK"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MAJOR CORRECTNESS Mark unresolved tool calls as unset

A tool call with no inline result that never receives a matching result remains OK, so downstream code treats its unobserved outcome as successful instead of unknown. Set its status to UNSET until a result arrives.

Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In `python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py`, lines 450–469, use the result-presence information so a call without an inline result starts as `UNSET` unless it is an error; keep successful/error statuses for observed results. Ensure separately arriving results update the status appropriately.

)
tool_span.end_time = max(tool_span.end_time, step_ts)
if current_turn is not None:
current_turn.end_time = max(current_turn.end_time, step_ts)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

NIT TIMING Update the turn that owns a late tool result

A result arriving after a new user event extends the new current_turn, while the tool’s original parent remains closed before its child. The trace then shows a tool outside its owning turn and an overstretched next turn.

Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In `python/src/agentplay/_core/ingestion/coding_agent/_sources/local/parsers/windsurf.py`, line 409, a late result updates `current_turn`, which may not own the tool. Resolve the turn by `tool_span.parent_id` and extend that owner so late results cannot stretch a later turn or leave the tool outside its parent.

@adityajha2005

Copy link
Copy Markdown
Contributor

hey @gorky117-cell can you check it out once?

…windsurf-parser

Signed-off-by: gauravatwork117 <gauravatwork117@gmail.com>
@gorky117-cell

Copy link
Copy Markdown
Author

@adityajha2005 Checked and resolved! Merged upstream/main, reconciled all conflicts cleanly alongside the new Command Code parser and v0.2.6 updates, and verified all 54 Windsurf and taxonomy test suites pass. Branch is clean and ready to merge!

This branch has not been deployed

No deployments
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.

Add a parser for Windsurf

3 participants