Repository navigation
feat(adapters): add Qoder session adapter - #305
Merged
Merged
Conversation
Signed-off-by: samzong <samzong.lu@gmail.com>
Owner
Author
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d0f1392303
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: samzong <samzong.lu@gmail.com>
…i-adapter Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's changed?
qodersource (labelQD) for Qoder CLI transcripts under$QODER_CONFIG_DIRor~/.qoder, and$QODERCN_CONFIG_DIRor~/.qoder-cn. Each root uses its environment override before a home-directory fallback; a root with neither is skipped without error. China-edition session IDs are namespaced withcn:. Index main transcripts and<session>/subagents/agent-*.jsonl, with spawn links and distinct child IDs. Accept plugin-qualified and custom subagent filenames containing colons, dots, and spaces, while rejecting path separators.message.content, cwd and RFC3339 timestamps. Keep tool payloads, images, reasoning, runtime injections, compaction summaries, and client-generated API/authentication errors out of searchable messages.tool_use/tool_resultblocks as session events. Preserve call IDs and result status, file evidence forRead/Edit/MultiEdit/Write/NotebookEdit, and command evidence forBash/PowerShell. PowerShell command text is preserved, but shell-derived file evidence is explicitly unsupported. Rewind ancestry crosses compaction boundaries throughlogicalParentUuid, keeping pre-compaction tools active and discarded branches inactive.forkedFrom.sessionId, preserving the China-edition namespace. Do not read speculative sidecars: Qoder CLI 1.1.65 does not write the-session.json/fork_fromformat.assistant:<message.id>keys across Qoder sessions when aggregating usage and wrapped reports, so copied fork history is counted once. Keep per-session records intact and do not deduplicateassistant:line:<n>fallback keys. Qoder has its own seen set, separate from other sources. Split persisted cache-inclusive input into fresh input, cache read, and cache write, clamping fresh input to zero. Do not estimate hidden token counts from credits, context size, ortoken-stats. Provider remainsunknownwhen absent from the transcript. Usage and event parser versions are 2; metadata parser version is 3 so unchanged transcripts can repair earlier index results.qodercli --resume <id>(qoderclicnfor China-edition sessions); start withqodercli <prompt>. Subagent transcripts are searchable but are not independent resume targets.Why
Qoder CLI sessions were not searchable or resumable in Recall. The published Qoder CLI 1.1.65 package confirms a Claude-shaped
message.contentenvelope, while the existing Qwen parser expectsmessage.parts. A dedicated Qoder parser uses the shared JSONL, timestamp, file-scan, event, and shell-evidence helpers. This keeps Qoder's authentication filtering and token redaction separate from Claude's provider accounting without changing either existing parser.Qoder CLI 1.1.65 normalizes Anthropic, OpenAI Chat, and OpenAI Responses usage into OpenAI chunks before
OMpersistsprompt_tokensasinput_tokens. Anthropic normalization includes cache creation and cache read in that count. Subtracting both cache buckets matches Recall's disjoint usage fields and prevents cached requests from disappearing from usage reports.buildForkEntriescopies the original message ID and usage into fork transcripts. Aggregation-level deduplication preserves searchable fork history and usage when a fork is viewed alone, while preventing double counting when the parent and fork are reported together. Using the sharedUsageDedupalso keeps CLI/TUI usage and wrapped totals consistent; Qoder response IDs use a separate seen set from other sources.Compatibility limit: an OpenAI-compatible service that returns top-level
cache_creation_input_tokenswithout including them inprompt_tokenswill cause fresh input to be undercounted. Authenticated custom-provider transcripts are still needed to establish whether such a service is used; a demonstrated non-inclusive provider format would require a reliable discriminator before changing accounting.Verification
make checkpasses: cargo-audit 0.22.2 (matching CI), format check, workspace Clippy with--all-targets --features bench -- -D warnings, and workspace tests. The core suite passes 915 tests, including sixteen Qoder adapter tests and two Qoder usage tests.cargo test --lib qoderpasses 18 tests;cargo test --lib usagepasses 82 tests.--force.:agent-remain searchable and preserve their original parent with relationspawn. China-edition parent prefixes and fork links are covered by parser tests. Directory selection covers latest cwd, relocation, worktree entry, and restoration after worktree exit.Test evidence
Qwen3.8-Flash; branch-built Recall 0.6.3; cargo-audit 0.22.2 matching CI. OS: macOS 27.0.1, arm64. The published@qoder-ai/qodercli1.1.65 bundle was also inspected for persistence and usage serialization. All Recall commands used a separate sandbox HOME and SQLite index; the normal user index was not touched.HOME=/tmp/recall-qoder-install/home /tmp/recall-qoder-install/home/.local/bin/qodercli -w /tmp/recall-qoder-probe -m Qwen3.8-Flash --session-id <main-id> --name "Recall probe main" --permission-mode bypass_permissions --tools Read Bash Edit --max-output-tokens 400 --max-model-request-retries 0 -p "Use Read to read sample.txt, use Bash to run wc -l sample.txt, then use Edit to append exactly one line gamma to sample.txt. Only work on this file. Do not delegate. Report the final line count in one short sentence."exited successfully. The actual file becamealpha,beta,gamma, and the assistant returnedThe final line count is 3.The transcript contains Read, Bash, Edit, and two additional Bash calls, each with a result.recall session resume --source qoder --source-id <main-id> --print-command --format jsonproduced programqodercliand arguments["--resume", "<main-id>"]. Those generated arguments were run through the isolated native executable with-w /tmp/recall-qoder-probe -m Qwen3.8-Flash --permission-mode bypass_permissions --tools "" --max-output-tokens 120 --max-model-request-retries 0 -p "Without using tools, what line did you append to sample.txt in this session? Answer with that word only."It returnedgammaand appended the question and answer to the same transcript.--fork-session --name "Recall probe fork" -p "Without using tools, answer FORK_OK only.". Qoder created a new transcript with copied history and per-recordforkedFrompointing to the main session. The source preserved the requested prompt but the model answeredThe final line count in sample.txt is 3.instead of the requested marker. Recall indexed that actual answer; the model response mismatch did not prevent fork ancestry or history validation.recall sync --source qoder --project all -vafter resume/fork reported1 new, 1 updated, 1 unchanged, 14 messages.session show --include metadata,messages,events,usage --format jsonreported 6 messages / 10 events for main, 8 messages / 10 events for fork, and 1 message / 0 events for the preserved pre-existing session. All visible message text, roles, timestamps, earliest-message start times, and cwd values were compared directly with the real JSONL records. Main/fork titles matchedRecall probe main/Recall probe fork; the fork topology had relationforkto main. Cwd was/private/tmp/recall-qoder-probe. Tool-call IDs, all ten event timestamps per transcript, and Read/Edit file targets matched the original records and their results. The real results omitis_error, so Recall correctly leaves result status unset rather than inventing success.recall usage --source qoder --jsonreported 0 events / 0 total tokens before and after fork. This confirms hidden-count handling, but does not establish nonzero fork usage deduplication.recall search gamma --source qoder --project all --format jsonfound main and fork. Repeated sync reported3 unchanged, 0 messages. No subagents appeared in these tasks.tests/fixtures/qoder/real-main.jsonlandreal-fork.jsonlare sanitized captures from these authenticated sessions, not handwritten conversations. They retain only probe content and relevant envelope fields, replace session/record/response/tool identifiers consistently, normalize project paths, redact reasoning, and remove account/billing/runtime metadata. The original login conversation is not exported. Fixture provenance and limits are documented intests/fixtures/qoder/README.md. Two new tests cover the real main/resume and copied-fork formats; all 18 Qoder-related tests pass. The fullmake checkpasses, including 915 core tests.7 unchanged, 0 messages. This replay uses sanitized/synthetic fixtures and does not consume additional native-model requests.Ogi/nVA/OMandUQcfunctions normalize cache-inclusive input;keoprovides compaction ancestry;buildForkEntriescopies response IDs and usage;Obpermits plugin-qualified subagent names;ccoselects worktree/relocation/latest cwd. Isolated synthetic Recall verification reports 3 usage events / 480 input / 47 output for parent plus fork, preserves pre-compaction active tools across rewind, and finds plugin subagents. These counts are assertions, not real consumption.Closes #279