Add pipeline composition DSL for multi-model workflows
Author: jonathan-fulton
Pull request: yes

## What does this PR do?

This PR introduces a declarative pipeline composition system that enables chaining multiple HuggingFace pipelines into unified workflows. It provides a clean, Pythonic API for building multi-model applications without manual data transformation code.

## Motivation

Modern AI applications increasingly require **multi-model workflows**:
- Image captioning → translation → text-to-speech
- Document OCR → summarization → question answering
- Speech recognition → sentiment analysis → response generation

Currently, users must write boilerplate code to:
1. Extract the right fields from each pipeline's output
2. Transform data between incompatible formats
3. Handle errors across the chain
4. Manage device placement for multiple models

This PR solves these problems with a simple `compose()` function.

## API Examples

### Basic Composition
```python
from transformers import pipeline
from transformers.pipelines.compose import compose

# Chain image-to-text and translation
workflow = compose([
    pipeline("image-to-text", model="Salesforce/blip-image-captioning-base"),
    pipeline("translation", model="Helsinki-NLP/opus-mt-en-de"),
])

# Execute the workflow
result = workflow(image="photo.jpg")
# Returns: [{"translation_text": "Ein Foto einer Katze"}]
```

### Custom Adapters
```python
workflow = compose(
    pipelines=[
        pipeline("image-to-text"),
        pipeline("summarization"),
        pipeline("text-to-speech"),
    ],
    adapters={
        (0, 1): lambda x: x[0]["generated_text"],
        (1, 2): lambda x: x[0]["summary_text"],
    }
)
```

### Error Handling
```python
# Retry failed stages with exponential backoff
workflow = compose(
    pipelines=[...],
    error_handling="retry",
    max_retries=3,
    retry_delay=1.0,
)

# Or skip failed items in batch processing
workflow = compose(pipelines=[...], error_handling="skip_failed")
```

### Streaming Intermediate Results
```python
for stage_result in workflow.stream("input.jpg"):
    print(f"Stage {stage_result.stage}: {stage_result.elapsed_ms}ms")
    print(f"Output: {stage_result.output}")
```

### Batch Processing
```python
from transformers.pipelines.compose import compose_batch

results = compose_batch(workflow, ["img1.jpg", "img2.jpg", "img3.jpg"])
```

## Features

- **`compose()`** - Factory function for creating pipeline chains
- **Auto-inferred adapters** - Automatic data transformation between common pipeline types (image-to-text → translation, translation → summarization, etc.)
- **Custom adapters** - Override adapters for specialized transformations
- **Error handling strategies**:
  - `"raise"` - Fail immediately on error (default)
  - `"skip_failed"` - Log warning, stop chain gracefully
  - `"retry"` - Retry with exponential backoff
- **Streaming** - Yield `StageResult` after each stage for progress monitoring
- **Batch processing** - Process multiple inputs with `compose_batch()`
- **Timing** - Automatic timing for each stage

## What's Included

- `src/transformers/pipelines/compose.py` - Core implementation
- `tests/pipelines/test_pipelines_compose.py` - 37 comprehensive tests
- Exports added to `pipelines/__init__.py`

## Future Work (Out of Scope)

- DAG/branching pipelines (non-linear composition)
- Conditional routing based on intermediate outputs
- Parallel execution of independent branches
- Memory-aware device distribution (`device_map="auto"`)
- Model quantization integration

## Testing

All 37 tests pass, covering:
- Basic composition and chaining
- Adapter system (auto-inference + custom)
- All error handling strategies
- Streaming support
- Batch processing
- Edge cases

## Who can review?

@Narsil @sgugger - Pipeline infrastructure


Comments:
Okay woah, tell your code agent to cool it! Pipelines are usually intended as a high-level API for newcomers, so adding a composition DSL kind of goes against the spirit. Users who want to do more advanced things like that should probably just run the models directly without pipelines.

Fair point @Rocketknight1! You're absolutely right - pipelines are meant to be a simple, approachable API, and adding a composition DSL overcomplicates that. Users who need multi-model workflows should work with the models directly.

Apologies for the overreach - closing this PR. Thanks for the feedback!