Skip to content

feat(adapters): add Warp agent conversation adapter - #306

Merged
samzong merged 8 commits into
mainfrom
feat/warp-adapter
Oct 7, 2026
Merged

samzong merged 8 commits into
mainfrom
feat/warp-adapter

Conversation

@samzong

@samzong samzong commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

What's changed?

  • Add the warp source (label WP). Discover Stable and Preview databases in the standard macOS, Linux, and Windows directories, including macOS group-container and Application Support fallback locations, tui/warp.sqlite, Linux XDG_STATE_HOME, and Windows LOCALAPPDATA. Index duplicate native conversation IDs once, preferring the earlier canonical path.
  • Read agent_conversations and protobuf agent_tasks.task through a read-only SQLite snapshot with a busy timeout. Keep user/assistant text, source timestamps in milliseconds, task descriptions, and working directories. Deduplicate message IDs and keep tool directories separate across interleaved tasks.
  • Exclude parent-agent, wake, schedule, automation, and server-synthesized query origins from user text. Retain direct client/integration input, Public API input, unknown origins, and unattributed task queries; the origin records the delivery mechanism rather than proving authorship. Ignore system/debug messages.
  • Record actual tool calls and results as session events, with file evidence for reads, edits, creation, deletion, and moves. Keep shell execution output and exit status. A shell result adds file evidence only when its executed command differs from the associated call or the call is absent. Match calls by tool ID regardless of timestamp ordering. Event parser version 3 backfills existing readable sessions without duplicating call/result file evidence.
  • Record usage only from explicit per-request RequestMetadata.charges token counts. Keep model/category/origin and separate input, output, cache-read, and cache-write counts. Deduplicate message-based usage keys across forks in the shared report accumulator while preserving per-session records. Do not infer usage from conversation totals or billing values; provider remains unknown when absent from the source.
  • Map conversation_data.parent_conversation_id to a subagent thread with a spawn parent link through the existing metadata backfill path.
  • Accumulate sessions and scan statistics directly across database paths. Isolate native database read failures: warn and scan the remaining paths, retaining sessions and statistics already streamed. Recall index-write failures still stop the scan. Skip malformed conversations while retaining readable ones, including later rows in the same database after invalid UTF-8 or BLOB metadata.
  • Require both agent_conversations and agent_tasks; the native migration creates them together. Skip taskless conversations so a handoff that transfers task ownership cannot replace already indexed assistant messages, events, or usage with user-only input.
  • Apply Today/7d/30d cutoffs before decoding old task blobs. Check both conversation and task modification times, include boundary timestamps and unknown timestamps, and bypass this optimization for forced scans.
  • Resolve result tool names from all conversation calls before chronological traversal, including results that precede their calls or arrive in interleaved tasks.
  • Warp uses a 200-conversation retention cap, evicting whole inactive trees; active trees can exceed the cap. The adapter does not reconcile source deletions, so already indexed history is retained after eviction or task transfer.
  • Use prost with a partial local protocol definition containing only fields needed for indexing. Other native fields and accepted query-origin payloads are skipped as unknown fields; they do not suppress user text. No migrations, source mutations, or additional persistent adapter state. Retain the Junie and Zed adapters from main alongside Warp, including their event-backfill registrations.
  • Leave resume/start unsupported: the inspected warp://conversation/... handler requires a server conversation token, and no verified local CLI accepts a native conversation ID or an initial local-agent prompt.

Why

Warp conversations were not searchable in Recall. Query history alone loses real assistant text and detailed tool records. Warp persists the complete task protobuf, providing the requested messages, events, and explicit token counts without synthesizing them from aggregates. Treating absent task rows as missing source data preserves Recall history when Warp transfers task ownership during handoff. Native timestamps are parsed before cutoff comparisons, preserving timezone offsets and conservative handling of unknown timestamps without decoding old payloads. Collecting call metadata once preserves chronological event order while making result names independent of traversal order.

Verification

  • make check: CI-pinned cargo-audit 0.22.2, format, workspace Clippy with --all-targets --features bench -D warnings, and all workspace tests (921 core tests plus extension tests).
  • Twenty-three Warp adapter tests and a shared usage regression test cover official wire/origin decoding, read-only WAL snapshots, task-local cwd, message ordering and duplicate IDs, taskless sessions, corrupt databases, per-conversation metadata failures, time-window filtering before task decoding, interleaved results preceding calls, propagation of index-write errors, shell call/result evidence, changed/orphan commands, parent metadata, multi-database discovery, usage-only/restricted scans, and omission of aggregate-only usage/tools.
  • Synthetic fixtures and an allowlisted, sanitized real probe task encoded independently with libprotoc 36.1 using Warp's official protocol revision 00cdd6726f28fb6b32a6712f0ca3264dbd0956a1. The SQL fixture is a minimal schema derived from Warp's upstream migration, not an installed database dump.
  • Sandbox CLI checks: sync, JSONL export, assistant keyword search, repeat sync, forced event backfill, usage reporting, all eight macOS discovery paths, source eviction, task ownership transfer, and a corrupt primary database with a readable fallback. The actual read-only MCP file_history endpoint also verifies shell evidence after event-version backfill. Sanitized real-fixture CLI replay verifies Stable/Preview accumulation, duplicate native IDs, corrupt primary-database isolation, and repeat sync.

Test evidence

  • Environment: macOS 27.0.1 (26A434), Apple Silicon; Recall 0.6.3 built from this branch, Rust/Cargo 1.96.0, cargo-audit 0.22.2, prost 0.14.4, libprotoc 36.1, Python protobuf 7.36.2 for independent decoding. make check passes audit, format, workspace Clippy, and all workspace tests (921 core tests plus extension tests).
  • Real session: Warp 0.2026.09.30.08.29.01, Grok 4.7 (grok-4-7-low, display name grok 4.7 (low)). The user used their own logged-in account to ask the agent to read sample.txt, run wc -l sample.txt, and append gamma in /tmp/recall-warp-probe. The verifier did not log in, configure a gateway, or operate Warp. The final file was independently checked as alpha, beta, and gamma, each on its own line.
  • Source: the user ran SQLite .backup inside Warp's terminal to produce a consistent snapshot. The snapshot was placed at ~/Library/Application Support/dev.warp.Warp-Stable/warp.sqlite in a private sandbox HOME, exercising the macOS Stable Application Support fallback. A probe-only sync returned status: created, message_count: 2; repeat sync returned status: unchanged. Export was compared against only the probe's official-protocol-decoded task before any other sessions were indexed.
  • Messages and metadata: one user prompt and one assistant reply matched the source text exactly. The cwd is /tmp/recall-warp-probe; file evidence resolves the read target to /private/tmp/recall-warp-probe/sample.txt. Message timestamps are 1791387715621 and 1791387728192; source modification time maps to 1791387729000. The title is Count Lines And Append Text In File. The source has no parent conversation, so Recall leaves the thread role unspecified and emits no parent link.
  • Events: seven events, comprising four calls (one server call, one read, and two shell commands) and three results. Both shell commands have successful results with exit code 0. The recorded output shows 2 sample.txt, then 3 sample.txt followed by alpha/beta/gamma. Event timestamps and call associations matched the native task. The append is represented by its actual shell command, rather than a fabricated edit-tool event.
  • File evidence limitation: the read call has a file-read record. The shared shell evidence parser marks both wc and the command containing ordinary append redirection as unsupported, so these shell events retain their commands/output but have no inferred file records. Matching results add no duplicate file evidence. Supporting these shell forms is separate from decoding the Warp task.
  • Usage: the real Grok task contains no RequestMetadata messages; Recall emits zero usage events. Conversation-level billing/usage metadata is not converted into inferred token counts. Real per-request classified token counts were not present in this session.
  • Other sessions: the snapshot contained three conversations and two tasks. After the probe-only check, an all-source Warp sync reported three candidates and two parsed sessions: Sync: 1 new, 0 updated, 1 unchanged, 2 messages. The other conversation with a task indexed successfully; the one without a task was skipped. Only indexing status was inspected for these conversations; their contents were not exported or included in fixtures.
  • macOS access restriction: with the real HOME, a read-only SQLite open of the native group-container database failed with unable to open database file. recall sync --source warp --backfill-events --dry-run --project all -v returned exit code 0, Found 0 sessions, and a WARN containing opening Warp database read-only: unable to open database file / SQLite error 14. No sync-wide failure occurred. This command uses a read-only Recall store; --dry-run requires --backfill-events. No privacy/security settings were changed or access controls bypassed.
  • Real fixture: probe.textproto and probe.bin retain allowlisted probe content and actual timestamps/variants, using invented stable IDs. Account/user identifiers, server/conversation tokens, credentials, project context, attachments, reasoning text, and other conversation data were removed. The fixture README records provenance and sanitization; the payload was reserialized with the official protocol, not copied unchanged. A new adapter test covers the observed messages, metadata, read success, commands/results, and absent usage/topology.
  • Synthetic coverage remains: explicit per-request token categories, fork usage deduplication, all query origins, subagent topology/backfill, read-only WAL snapshots, shell move evidence/backfill, task ownership transfer, source eviction, corrupt database/row isolation, early time-window filtering, results preceding calls, and all eight macOS GUI/TUI discovery paths. Earlier synthetic MCP file_history verification confirms duplicate-free supported command evidence. These synthetic checks are not real-session acceptance for those variants.
  • Isolation and cleanup: private sandbox HOME/indexes under /tmp/recall-warp-*; only verified sandbox worker PIDs were stopped. The real Recall database's identity, size, and modification time were unchanged. /tmp/recall-warp-copy and all sandbox copies/private indexes from this verification were deleted. The probe directory was not modified by the verifier.
  • Still unverified: successful direct indexing of the protected group container from this terminal or from Warp's terminal; real RequestMetadata token categories, forks/subagents, Preview/TUI release payloads, Linux/Windows discovery, BYOK, and native resume/start. No verified local Warp CLI supports resume/start with a native local conversation ID. Real macOS fallback-path decoding was tested through the user-exported snapshot, not through permission changes.

Closes #291

Decode persisted task protobufs instead of synthesizing assistant messages and tool calls from query history or aggregate statistics.

Verified with make check and isolated CLI sync, export, search, and event backfill against synthetic fixtures encoded with the official Warp protocol. Real Warp conversation acceptance remains pending because the installed app did not initialize.

Signed-off-by: samzong <samzong.lu@gmail.com>
@samzong

samzong commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-07T14:05:27.931915Z 2ca1be9 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ca1be958e

ℹ️ 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".

Comment thread src/adapters/warp.rs Outdated
fn scan_for_sync_output(
&self,
context: &AdapterSyncContext,
_since_ts: Option<i64>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply the sync cutoff before decoding Warp task blobs

When the user selects the Today, 7d, or 30d sync window, since_ts is supplied specifically to bound adapter work, but this implementation discards it and queries and protobuf-decodes every task in every conversation. The generic sync cutoff runs only after each RawSession has been constructed, so large Warp databases still incur a complete database read and protobuf decode on every sync; pass the cutoff into the query, while disabling it for forced scans.

Useful? React with 👍 / 👎.

Comment thread src/adapters/warp.rs Outdated
})();
match parsed {
Ok(Some(mut raw)) => {
let data: String = row.get(2)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep metadata reads within the per-session failure boundary

If one conversation_data value cannot be converted to UTF-8 text—for example, a damaged row or a BLOB stored in SQLite's dynamically typed column—this ? exits scan_db_with_seen rather than warning and skipping that conversation. scan_paths then moves to the next database, so every readable conversation ordered after the bad row in this same database is silently omitted; handle this read in the per-row parsed result just like the ID, timestamp, and task decoding.

AGENTS.md reference: src/adapters/AGENTS.md:L17-L18

Useful? React with 👍 / 👎.

Comment thread src/adapters/warp.rs Outdated
Comment on lines +377 to +379
let name = tool_names.get(&result.tool_call_id).cloned().flatten();
let command = shell_commands.get(&result.tool_call_id).map(String::as_str);
session_events.push(result_event(&result, context, name, command, active_cwd));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve result tool names independently of traversal order

When a non-shell tool result sorts before its corresponding call because its timestamp is earlier or the records come from interleaved tasks, tool_names has not yet been populated and the result event is emitted without a name even though the result itself identifies read_files or apply_file_diffs. The shell-command map is already precomputed for this ordering case; precompute tool names similarly or derive the known result variant directly.

Useful? React with 👍 / 👎.

Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>
Signed-off-by: samzong <samzong.lu@gmail.com>

# Conflicts:
#	src/usage.rs
@samzong
samzong marked this pull request as ready for review October 7, 2026 16:27
@samzong
samzong merged commit a3a0480 into main Oct 7, 2026
4 of 5 checks passed
@samzong
samzong deleted the feat/warp-adapter branch October 7, 2026 16:27
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 Warp agent conversation adapter

1 participant