feat: add QwenPaw agent support - #694
Conversation
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
|
Can you include some santized sample qwenpaw files for this? and ideally also a script that can be used to regenerate them using the cli of the agent? Alternatively a stable link to where in the qwenpaw source code these sessions are serialized so that we have something to test against. |
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
QwenPaw:https://github.com/agentscope-ai/QwenPaw |
|
Took a review pass on this (file-based agent, so the heavy DB-backed sync hazards mostly don't apply). The roborev bot already drove out the serious mechanical defects commit-by-commit — the compile-breaking registry/merge conflict, path traversal, mtime-in-seconds, What's goodClean separation of discovery / find-source / parse. The subdir-in-ID fix is correct and well-tested; traversal hardening ( 1. Message writes use the append-only path, but QwenPaw rewrites the whole file (the one to resolve)
That path is correct only for strictly append-only sources with stable ordinals (Claude/Codex JSONL). QwenPaw isn't that shape:
If that array is ever compacted, summarized, reordered, or has its latest message finalized in place — all common in agent-memory frameworks, and plausible since every save rewrites the whole file — ordinals shift and the append path silently keeps stale/misaligned rows. This is the hazard the engine comment at Suggestion: default 2. PR description is stale / invertedThe description still describes the original implementation: sessions stored as More than a doc nit: the pivot from 3.
|
roborev: Combined Review (
|
|
I can take it from here if that's ok |
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
- Use shared lineReader for QwenPaw parser - Store QwenPaw mtime in nanoseconds and populate tool-result length - Read QwenPaw sessions from sessions/, not dialog/ - Drop redundant compactJSON to satisfy modernize linter - Encode QwenPaw sessions/ subdir in session ID to prevent collisions - Add sanitized QwenPaw fixtures and regeneration script - Reject path traversal in QwenPaw source resolution - Route QwenPaw sessions through full-replace write path - Preserve QwenPaw workspace on resync and harden fixture generator - Reject ":", "~", and URL delimiters in ID parts across discovery, parsing, and source lookup to prevent ambiguous/unopenable IDs - Harden the fixture generator against symlinked deletion targets Co-Authored-By: Wes McKinney <wesmckinn+git@gmail.com>
Keep the traversal test's escape file inside the t.TempDir() tree instead of writing above root. Add TestQwenPawFixtures so the checked-in testdata/qwenpaw fixtures are discovered, parsed, and asserted in CI, catching malformed or drifting fixtures.
roborev: Combined Review (
|
':' is illegal in Windows filenames, so tests that created colon-named files or directories failed on windows-latest CI. Make the workspace parse-validation case cross-platform by carrying ':' in the project argument instead of a directory name, and skip the cases that require a colon on disk (subdir derivation, collision discovery, classify scan) on Windows. TestIsValidQwenPawIDPart still covers the rejection logic on every platform.
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).