feat: add QwenPaw agent support#694
Conversation
Adds the QwenPaw coding agent to the registry and sync pipeline. QwenPaw stores daily conversation transcripts as <workspace>/dialog/<YYYY-MM-DD>.jsonl under ~/.copaw/workspaces/. The parser handles Anthropic-style content blocks (text, thinking, tool_use, tool_result) with system-role carriers for tool results, which map to RoleUser + IsSystem so they stay distinguishable from real user turns without inflating UserMessageCount. Timestamps use the "YYYY-MM-DD HH:MM:SS.fff" local-time format. Raw session IDs use the form "<workspace>:<date>", yielding full IDs like "qwenpaw:default:2026-04-19".
roborev: Combined Review (
|
Switches the QwenPaw JSONL loop from a bufio.Scanner with an 8 MiB cap to newLineReader(f, maxLineSize), matching the other JSONL parsers in this package. Two behavior improvements: - The line cap rises from 8 MiB to the shared 64 MiB maximum, so legitimate large tool-result lines no longer abort the parse. - Oversized lines are silently skipped (per the lineReader contract) instead of failing the whole session; the surrounding messages still sync. Adds TestParseQwenPawSession_OversizedLineSkipped to lock in the new behavior.
roborev: Combined Review (
|
Two review-driven fixes on the QwenPaw parser: - FileInfo.Mtime now uses info.ModTime().UnixNano() instead of .Unix(). The sync engine compares File.Mtime against os.Stat in nanoseconds, so the previous seconds-precision value would never match shouldSkipByPath after the first sync, forcing every QwenPaw file to reparse on every pass. - ParsedToolResult.ContentLength is now derived from block.Output via the shared toolResultContentLength helper. Without it, default- blocked categories like Read lost their only retained result-size signal (result_content_length persisted as zero). Adds TestParseQwenPawSession_FileMtimeIsNanoseconds and extends TestParseQwenPawSession_ToolUseAndResult to assert ContentLength on the paired tool result.
roborev: Combined Review (
|
Adds the QwenPaw coding agent to the registry and sync pipeline.
QwenPaw stores daily conversation transcripts as
<workspace>/dialog/<YYYY-MM-DD>.jsonlunder~/.copaw/workspaces/.Each runtime hosts multiple agent workspaces (
default,fund_manager,note_keeper,researcher, ...), and each workspacelogs one JSONL file per active day.
The parser handles Anthropic-style content blocks (
text,thinking,tool_use,tool_result) with one QwenPaw quirk: tool results live inrole: "system"messages rather than user messages. Those map toRoleUser + IsSystemso they remain distinguishable from real userturns without inflating
UserMessageCount. Timestamps use the"YYYY-MM-DD HH:MM:SS.fff"local-time format and are parsed viatime.ParseInLocation(..., time.Local), mirroring the Hermes parser.Raw session IDs use the form
<workspace>:<date>, yielding full IDslike
qwenpaw:default:2026-04-19. Discovery walks<root>/<workspace>/dialog/*.jsonl; the watcher path classifier andproject extraction in
internal/sync/engine.gowere extended to match.Scope / non-goals:
dialog/*.jsonlis parsed. Thesessions/*.jsonagent-memorysnapshots overlap with dialog content and are skipped for now.
inbox_traces/*.json(cron run traces) andinbox_events.jsonarenotification-shaped, not conversations, and are out of scope.
token_usage.jsonis not wired up; itis keyed by day/model rather than by session.
Reviewers should look at:
internal/parser/qwenpaw.go— discovery, source resolution, parseloop, role mapping, timestamp parsing.
internal/parser/qwenpaw_test.go— table-driven coverage of thehappy path plus malformed lines, empty content, missing timestamps,
multiple tool_use blocks, and the system-role tool_result mapping.
internal/sync/engine.go— four insertion points (watcher pathclassification, process dispatch switch, new
processQwenPaw,project extraction case).
internal/parser/types.go— newAgentQwenPawconstant andregistry entry (
EnvVar: QWENPAW_DIR,DefaultDirs: [".copaw/workspaces"],IDPrefix: "qwenpaw:").frontend/src/lib/utils/agents.ts— label/color entry (cyan,matching
Qwen Code; can be re-tinted separately if a distinctvisual identity is desired).