Deferred follow-ups from #33 (items 4 and 5). Items 1–3 shipped in #55 / v0.9.0.
1. Replace Option<serde_json::Value> with a typed ProviderMetadata enum
Content::ToolCall.provider_metadata is an untyped bag with no schema, no namespacing, and no compile-time link between metadata shape and producing provider. Suggested shape (from #33):
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "provider", rename_all = "snake_case")]
pub enum ProviderMetadata {
Gemini { thought_signature: String },
// Anthropic { cache_control: ... },
// OpenAi { reasoning_id: String },
}
Implementation notes:
- Needs a serde back-compat path for persisted messages that carry the current raw-JSON shape (untagged fallback or a migration).
- Both google.rs paths change (capture in the stream loop, echo in
content_to_google_parts / build_request_body).
- Since v0.9.0,
Content::ToolCall is #[non_exhaustive] and constructed via Content::tool_call_with_metadata(), so this migration is no longer a hard downstream break — it can ship in any minor release.
2. Drop the google-fc- magic-string coupling
content_to_google_parts and build_request_body detect synthetic tool-call IDs via id.starts_with("google-fc-"). Fold a was_synthetic marker into the typed metadata (rides along naturally with item 1) instead of coupling formatter and serializer through a literal prefix.
When to do this
Trigger: the moment a second provider needs provider_metadata (e.g. OpenAI reasoning IDs) — do both items together before shipping that provider, since that is when the key-collision risk becomes real. Until then this is not urgent.
Deferred follow-ups from #33 (items 4 and 5). Items 1–3 shipped in #55 / v0.9.0.
1. Replace
Option<serde_json::Value>with a typedProviderMetadataenumContent::ToolCall.provider_metadatais an untyped bag with no schema, no namespacing, and no compile-time link between metadata shape and producing provider. Suggested shape (from #33):Implementation notes:
content_to_google_parts/build_request_body).Content::ToolCallis#[non_exhaustive]and constructed viaContent::tool_call_with_metadata(), so this migration is no longer a hard downstream break — it can ship in any minor release.2. Drop the
google-fc-magic-string couplingcontent_to_google_partsandbuild_request_bodydetect synthetic tool-call IDs viaid.starts_with("google-fc-"). Fold awas_syntheticmarker into the typed metadata (rides along naturally with item 1) instead of coupling formatter and serializer through a literal prefix.When to do this
Trigger: the moment a second provider needs
provider_metadata(e.g. OpenAI reasoning IDs) — do both items together before shipping that provider, since that is when the key-collision risk becomes real. Until then this is not urgent.