Repository navigation
feat(ingestion): add Windsurf parser for issue #26 - #34
gorky117-cell wants to merge 2 commits into
Conversation
EntelligenceAI PR SummaryAdds 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;
Review Scorecard
Issues found:
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 Evaluated against
|
WalkthroughAdds 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. ChangesFiles
Document Windsurf/Cascade as a supported coding agent, including its default data location, transcript formats, and Files
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
Register Windsurf tool names with the canonical taxonomy, including mappings for shell commands, file reads, searches, edits, and writes. Files
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. |
|
@Entelligence-AI /approve |
|
@gorky117-cell said:
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 |
|
All automated review feedback items have been resolved in commit
|
|
Resolve conversation" |
|
All automated review feedback items have been addressed and approved:
The PR is approved and ready for maintainer merge! |
|
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. |
56329e6 to
d45603d
Compare
|
@adityajha2005 Rebased against latest main and resolved all merge conflicts! All tests and linters are passing. |
| tool_span.status_code = "ERROR" | ||
| tool_span.attributes["code.edit_evidence"] = extract_edit_evidence( | ||
| tool_span.name, | ||
| tool_span.attributes.get("input.value", "{}"), |
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
|
hey @gorky117-cell can you check it out once? |
…windsurf-parser Signed-off-by: gauravatwork117 <gauravatwork117@gmail.com>
|
@adityajha2005 Checked and resolved! Merged |
What and why
This PR implements a robust parser for Windsurf conversation data to fulfill Issue #26.
read_file,edit,run_command,write_to_file) to canonicalagentplaytools (Read,Edit,Bash,Write, etc.) viatool_taxonomy.py.parsers/base.pyand local source indexing insource.py.tests/core/test_windsurf_parser.py. All core tests (590/590) pass successfully.Checklist
make checkpassesFixes #26