---
title: "Configurable LLM providers, Slack reviews, and Daytona Dockerfiles"
date: "2026-05-13"
---

<Warning>
**Run failure payloads now use structured failure objects.** Terminal run failures emit a nested `failure` value instead of relying on flat error, cause, or reason fields.

To migrate:
1. Regenerate API clients from the current OpenAPI schema.
2. Read terminal diagnostics from `failure.reason`, `failure.causes`, `failure.category`, and related structured fields.
3. Treat stage-level failure strings and terminal run failures as separate API surfaces.
</Warning>

## Configurable LLM providers and models

Fabro can now merge LLM provider and model catalog entries from settings. Teams can add OpenAI-compatible gateways, route through provider proxies, attach typed extra headers, map a Fabro model ID to a provider-specific `api_id`, declare model controls, and set per-speed pricing without waiting for a new built-in catalog entry.

```toml
[llm.providers.proxy]
adapter = "openai_compatible"
base_url = "https://llm-gateway.example.com/v1"

[llm.providers.proxy.auth]
credentials = ["env:ACME_GATEWAY_API_KEY"]

[llm.providers.proxy.extra_headers]
x-portkey-api-key = { env = "PORTKEY_API_KEY" }
x-portkey-config = { literal = "@bedrock-prod" }

[llm.providers.proxy.models."team-code-large"]
api_id = "provider-wire-model-name"
default = true
```

Provider values exposed by configuration, model routing, and the API are provider ID strings. Built-in names like `anthropic`, `openai`, and `gemini` still work, and custom IDs such as `proxy` now work wherever the selected catalog defines them.

## Slack review messages with context

Slack interview prompts now include the upstream stage response and an "Open in Fabro" link when the server has a web URL. Reviewers can see the plan summary or other context directly in Slack before choosing an answer.

Multi-button Slack gates also use unique button action IDs, fixing the `invalid_blocks` rejection that could prevent approval messages from appearing at all. Existing in-flight buttons remain compatible while new messages use the safer suffixed action IDs.

## Path-based Daytona Dockerfiles

Daytona snapshot configuration can now reference Dockerfiles by path from project or workflow TOML. Fabro resolves the path relative to the declaring TOML file, bundles the Dockerfile into run manifests, and rewrites it to inline content before sandbox creation.

```toml
[run.sandbox.daytona.snapshot]
dockerfile = { path = "./Dockerfile" }
```

## More

<Accordion title="API">
- Run failures now preserve public messages, source-chain causes, classifications, actor/signature metadata, and redacted exec output tails in one structured contract
- Billing APIs now expose provider, model, and speed identity so standard and fast usage can be priced separately
- Model catalog responses now use open-ended provider IDs instead of a closed provider enum
</Accordion>

<Accordion title="Workflows">
- Added catalog-aware LLM request control validation and per-speed billing lookup
- Added support for `dockerfile = { path = "..." }` in Daytona snapshot settings
- Added structured diagnostics for terminal run failures and failed-run commit state
</Accordion>

<Accordion title="Fixes">
- Fixed Graphviz parsing so multi-line DOT attribute blocks no longer require commas between every attribute
- Fixed multi-button Slack interview messages being rejected by Slack because every button shared the same `action_id`
</Accordion>

<Accordion title="Improvements">
- Built-in provider and model metadata now comes from settings-shaped catalog TOML files
- OpenAI-compatible provider aliases can use canonical catalog model IDs for billing while preserving provider-specific `api_id` values on the wire
- Public contribution docs now allow small outside pull requests as well as issue-first contribution paths
</Accordion>
