Extending
TramAI is designed to stay structured while remaining adaptable. This section covers the extension points you use when the default providers and behaviors are not enough and you need to integrate custom infrastructure.
In This Section
| Guide | Focus |
|---|---|
| Custom Providers | Implementing the ModelProvider SPI for non-standard or internal backends |
| Custom Interceptors | Adding cross-cutting behavior around operation execution |
| Custom Observers | Plugging in custom observation and telemetry behavior |
| MCP Integration | The internal MCP server adapter and what MCP capability does not exist yet |
When To Start Here
Start here when the default modules are close but not sufficient, and you need to tailor TramAI to your platform or internal tooling.
What You Can Extend Without Forking
These surfaces are supported extension points. Everything else is internal and can change without notice.
| Surface | Interface | Notes |
|---|---|---|
| Providers | dev.tramai.core.provider.ModelProvider | Registered explicitly through ProviderRegistry; conformance is proved by ProviderTck |
| Request/response rewriting | dev.tramai.core.observation.OperationInterceptor | Chainable; pass-through defaults on both methods |
| DLP scanning | dev.tramai.core.security.DlpInterceptor | Inspect and sanitize model outputs and tool results |
| Observation | dev.tramai.core.observation.OperationObserver | One observation per provider attempt |
| Engine events | dev.tramai.engine.EngineEventObserver | Event identities come from RuntimeEventCatalogue |
| Structured output | StructuredOutputHandler | Implement a handler when Jackson does not fit your payloads |
@ExperimentalTramaiInternalApi and @ExperimentalProviderTransportApi mark code that sits outside the stable compatibility promise. Opting in is fine; depending on it is a considered risk.
Constraints Every Extension Must Respect
These are enforced in the TramAI repository by verifyStaticSafetyGuards and verifyCancellationSafety, and they apply to your code too:
- No sensitive-payload logging — never log prompts, responses, tool arguments, tokens, or credentials.
- No
System.out/System.errin production code; use a logger. - Cancellation must propagate. In
catch (e: Exception)blocks callrethrowIfCancellation()fromdev.tramai.core.coroutines.rethrowIfCancellationbefore wrapping, logging, or swallowing. - No unbounded response-body reads; use the bounded helpers.
Contributing Back
If you are contributing to the TramAI repository rather than building on it, the contributor change guides cover the same surfaces from the inside, including the files that must change and the contract tests that gate each change:
Next Steps
- Testing & Observability — prove your extension deterministically
- Providers & Routing — routing, fallback, and resilience configuration
- Structured Output — the structured-output contract
- Production Hardening — budgets, circuit breakers, and secure baselines
