Skip to content

Gemini Export#59

Merged
benbaarber merged 5 commits into
mainfrom
ben/gemini-export
Apr 27, 2026
Merged

Gemini Export#59
benbaarber merged 5 commits into
mainfrom
ben/gemini-export

Conversation

@benbaarber
Copy link
Copy Markdown
Collaborator

No description provided.

…h Path

derive_path and extract_conversation were an incomplete pair: several
Turn fields either never got serialized into conversation.append extras
(stop_reason, environment, Turn.extra, tool-use results, delegations) or
were serialized but never read back (tool_uses, delegations, token_usage
in its nested form). Any ConversationView written to a Path and read
back lost those fields silently.

derive now writes them; extract reads them with fall-throughs so Claude's
bespoke top-level-key schema still decodes. build_environment,
build_inline_tool_uses, build_delegations, and build_turn_extra factor
out the readers; build_token_usage prefers the nested shape and falls
back to the top-level Claude keys.

Model attribution consolidates on the actor URI. derive_path stopped
writing a redundant "model" key into the append extras; extract reads
the model out of the step's agent:{model} actor via a new
model_from_actor helper that handles the agent:claude-code/tool:... sub-
actor form and the agent:unknown sentinel. A fallback to extras["model"]
keeps earlier Paths decoding.

Provider + session now recover from the {provider}://{session} artifact
key on the first conversation.append step, since shared derivation does
not emit conversation.init.
Adds a Gemini-side reverse of the existing forward path: any
ConversationView can be projected into a Gemini-native Conversation
that loads cleanly into `gemini --resume`. End-to-end this enables
moving a conversation from another harness (Claude in particular) into
a resumable Gemini session.

toolpath-gemini changes:

- New `project` module with `GeminiProjector: ConversationProjector<
  Output = Conversation>`. Sets `kind: "main"`, full UUID `sessionId`,
  populates `directories`. Synthesizes per-tool-call `description`,
  `displayName`, `renderOutputAsMarkdown`, `resultDisplay` from args
  and result text — real Gemini sessions carry these on every call.
- `provider::native_name(ToolCategory, &Value)` — reverse of
  `tool_category`. Picks Gemini's preferred native name for a generic
  category, using the call's args to disambiguate FileWrite (replace
  vs write_file) and FileRead (read_file vs read_many_files vs
  list_directory). The projector remaps foreign tool names through
  this; native ones pass through unchanged.
- `provider::build_gemini_extra` now preserves thought `description`
  alongside subject/timestamp so `Thought[]` round-trips losslessly.
- `paths::resolve_main_file(project, session_id)` — locates a main
  chat by either filename stem OR inner `sessionId` UUID, mirroring
  how Gemini CLI's `--resume <uuid>` resolves. `read_session`,
  `read_session_metadata`, and `session_exists` use it.
- `Tokens` fields gain `skip_serializing_if = "Option::is_none"` so
  partial usage (from foreign sources) omits absent fields instead
  of writing nulls.
- Foreign-namespace extras (e.g. `Turn.extra["claude"]`) are dropped
  during projection rather than flattening as top-level message
  fields, eliminating per-message JSON pollution.

toolpath-cli changes:

- `cmd_export::ExportTarget::Gemini` — `path export gemini --input
  <cache-id-or-file> [--project <dir>]`. Writes the resume-ready
  layout to `~/.gemini/tmp/<slot>/chats/`: flat
  `session-<ts>-<short>.json` main file (the `session-` prefix is
  mandatory for `--list-sessions` to find it) plus
  `chats/<session-uuid>/<sub>.json` for any sub-agents. Drops a
  `.project_root` marker. Bakes `projectHash` to match what Gemini
  computes from the same cwd.

toolpath-claude changes:

- `tool_category` and `tool_category_str` learn `MultiEdit` (FileWrite)
  and `Agent` (Delegation, alias for Task). Without these, Claude-
  derived path docs left those tools uncategorized and the projector
  couldn't remap them.

Format docs:

- `docs/agents/formats/gemini.md` documents two empirical constraints
  discovered while building this: the mandatory `session-*.json`
  filename prefix for CLI session enumeration, and the two-step
  `--resume <id>` resolution (stem match → inner sessionId scan).

Tests:

- 17 unit tests in `project.rs` covering content shape, role mapping,
  thoughts (meta + flattened-string fallback), tokens (gemini extras
  + common-token-usage fallback), tool calls (success/error/meta
  preservation), delegation unfolding, foreign-namespace dropping,
  Gemini-native message extras preservation, serde round-trip.
- 11 integration tests in `tests/projection_roundtrip.rs` exercising
  the full chain ChatFile -> ConversationView -> Path (serialized) ->
  ConversationView -> ChatFile, including a write-to-disk +
  GeminiConvo::read_conversation round-trip that uses the same code
  path Gemini CLI uses for --resume.
- 4 unit tests in `paths.rs` for the new `resolve_main_file` (stem
  match, inner-sessionId match, stem-preferred-over-id, no-match).
- 2 integration tests in `cmd_export.rs` for the new gemini variant
  (writes resume-ready layout + readable via library, rejects
  non-Path docs).
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 27, 2026

🔍 Preview deployed: https://da47bb17.toolpath.pages.dev

Comment thread crates/toolpath-cli/src/cmd_export.rs Outdated
Comment thread crates/toolpath-convo/src/extract.rs Outdated
Comment thread crates/toolpath-convo/src/extract.rs Outdated
Copy link
Copy Markdown
Contributor

@akesling akesling left a comment

Choose a reason for hiding this comment

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

LGTM

Comment thread crates/toolpath-cli/src/cmd_export.rs
@benbaarber benbaarber merged commit de54ba5 into main Apr 27, 2026
2 checks passed
@benbaarber benbaarber deleted the ben/gemini-export branch April 27, 2026 18:21
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.

2 participants