va-ai-api-bridge 0.1.7

Protocol translation primitives for AI API request and response shapes.
Documentation
# Getting Started

This guide shows the smallest useful SDK flow: decode one protocol into IR and encode it into another protocol.

## Install

Use the published crate from crates.io:

```bash
cargo add va-ai-api-bridge serde_json
```

Or add the dependencies manually:

```toml
[dependencies]
va-ai-api-bridge = "0.1.6"
serde_json = "1"
```

The package name uses hyphens on crates.io. Rust imports use underscores:

```rust
use va_ai_api_bridge::OpenAiChatTranslator;
```

## Translate a Request

```rust
use serde_json::json;
use va_ai_api_bridge::{AnthropicMessagesTranslator, OpenAiChatTranslator, WireTranslator};

let source = OpenAiChatTranslator;
let target = AnthropicMessagesTranslator;

let universal = source.decode_request(json!({
    "model": "gpt-4.1",
    "messages": [
        { "role": "system", "content": "You are concise." },
        { "role": "user", "content": "Say hello." }
    ]
}))?;

let anthropic_body = target.encode_request(&universal)?;
```

## Dispatch Dynamically

Use `translator_for_protocol` when the host route decides protocols at runtime.

```rust
use serde_json::json;
use va_ai_api_bridge::{translator_for_protocol, WireProtocol};

let source = translator_for_protocol(WireProtocol::OpenAiChat);
let target = translator_for_protocol(WireProtocol::AnthropicMessages);

let universal = source.decode_request(json!({
    "model": "chat-model",
    "messages": [{ "role": "user", "content": "Hello" }]
}))?;
let target_body = target.encode_request(&universal)?;
```

## Apply Media Capability Policy

Hosts should resolve the final target model before target encoding. If the host already has JSON model metadata, pass it directly:

```rust
use serde_json::json;
use va_ai_api_bridge::sanitize_unsupported_media_from_json;

let report = sanitize_unsupported_media_from_json(
    &mut universal_request,
    json!({
        "providerLabel": "DeepSeek",
        "model": "deepseek-v4-pro",
        "capabilities": {
            "inputModalities": ["text"]
        }
    }),
)?;
```

If the host has already deserialized its profile/catalog data, use the typed `ResolvedModelSpec`:

```rust
use va_ai_api_bridge::{sanitize_unsupported_media, ModelCapabilities, ResolvedModelSpec};

let model = ResolvedModelSpec {
    provider_label: Some("DeepSeek".to_string()),
    model: "deepseek-v4-pro".to_string(),
    capabilities: ModelCapabilities {
        input_modalities: vec!["text".to_string()],
        ..ModelCapabilities::default()
    },
    extensions: Default::default(),
};

let report = sanitize_unsupported_media(&mut universal_request, &model);
```

Run media policy before encoding the target protocol so unsupported `Image` or `File` blocks become safe text placeholders instead of being sent upstream.

## Run the Examples

```bash
cargo run --example translate_request
cargo run --example provider_adapter
cargo run --example media_policy
cargo run --example media_policy_typed
cargo run --example stream_events
```