Skip to content

Module Boundaries

This page is a maintainer map for deciding where code belongs. When in doubt, keep protocol conversion explicit and keep provider-specific behavior out of generic translation.

src/pipeline/inbound.rs

Detect inbound protocol from the HTTP path, parse JSON bytes, and map carrier errors before core preparation.

crates/proxai-core/src/ingress/

Normalize and validate structured inbound payloads before routing and translation.

crates/proxai-core/src/pipeline/

Carrier-independent façade that composes ingress, routing, translation, provider request adaptation, and response processing.

crates/proxai-core/src/observe.rs

Shared observer contract, closed core observation variants, and no-op default. No concrete sinks.

crates/proxai-core/src/protocol/

Wire structs, enums, and protocol-specific event payloads. No provider routing decisions.

crates/proxai-core/src/routing/

Compile model rules, select provider labels by request protocol/model, rewrite upstream models, and enforce strict protocol guards.

crates/proxai-core/src/translation/

Carrier-independent request/response/stream conversion between protocol pairs, with typed observations for legal adaptations.

crates/proxai-core/src/provider/

Carrier-independent provider request payload preparation, compatibility policy, structured response/error normalization, and typed adaptation observations.

src/provider/*/request

Application-side provider projection/summary extraction, JSON serialization, and request carrier assembly.

src/provider/*/transport

Upstream URL construction, provider-owned auth headers, HTTP send.

src/upstream/

Read provider status, headers, non-streaming body, and streaming byte carriers.

src/http_support/

HTTP response reconstruction, content-type helpers, header filtering, byte stream carriers.

src/error/

Domain error taxonomy and compact client-facing error projection.

src/observe/

Structured logs, capture phases, hints, and privacy-aware diagnostics.

QuestionPut it in
Does it parse a client request path or body bytes?src/pipeline/inbound.rs
Does it compose the complete structured request/response path without HTTP carriers?crates/proxai-core/src/pipeline/
Does it normalize or validate a structured inbound payload?crates/proxai-core/src/ingress/
Does it define a reusable core observation contract or event?crates/proxai-core/src/observe.rs
Does it define protocol JSON wire shape?crates/proxai-core/src/protocol/
Does it select a provider label by protocol/model?crates/proxai-core/src/routing/
Does it map a selected provider label to an HTTP transport?src/pipeline/provider_request.rs
Does it convert one protocol payload into another protocol payload?crates/proxai-core/src/translation/
Does it prepare a structured provider request value, rewrite its model, or adapt provider-local request fields?crates/proxai-core/src/provider/
Does it extract logging projections/summaries or serialize the provider request body?src/provider/*/request
Does it normalize a structured provider response, stream event, or error payload?crates/proxai-core/src/provider/
Does it add provider auth headers or build upstream URLs?src/provider/*/transport
Does it filter headers or rebuild an HTTP response?src/http_support/
Does it render client-facing errors?src/error/
Does it write logs or capture artifacts?src/observe/

proxai-core defines the shared Observer contract, closed Observation variants, and a no-op default. Core ingress, provider normalization, and translation emit typed variants through that contract. They do not select tracing, diagnostics files, capture storage, metrics backends, or any other concrete sink; the downstream application composes those implementations.

TranslationScope is an explicit request- and phase-scoped dependency. It must not be global, thread-local, or task-local. Pass &TranslationScope through pair entrypoints and semantic projections only when that path may emit adapted or dropped; pure wire conversions, From/TryFrom implementations without loss reporting, and outbound constructors remain scope-free. Fatal failures return through Result and must not also emit the same failure as an observation. This explicit scope model is preferred over returning a parallel projection/notice collection because streaming observations are naturally emitted as events arrive and the shared Observer already lets downstream callers collect them as data when needed.

For request-scoped code, emit stable lifecycle and domain events through ObserveContext. ObserveSinks then decides whether each point goes to logging, diagnostics, capture, or several sinks. The logging sink is the layer that translates an observation into a tracing event and chooses its level and output format.

SituationUse
Core legal-but-lossy adaptation or ingress compatibility eventA typed Observation variant through the shared Observer; the downstream decides the sink.
Request lifecycle, protocol/provider outcome, or failure contextObserveContext with a typed point.
Logging sink implementationDirect tracing; this is where level and formatting are selected.
Observation/capture subsystem failureDirect tracing to avoid recursively observing the observer.
Process startup, configuration, or background task without request contextDirect tracing.
Temporary local implementation debuggingtracing::trace!; promote it to an observe point if it becomes a recurring diagnostic signal.
AvoidWhy
Passing HTTP Response into crates/proxai-core/src/translation/Translation should stay pure at the carrier boundary.
Adding provider auth logic in translationAuth is provider transport behavior, not protocol conversion.
Treating provider names as protocol valuesProvider names are user labels and can be arbitrary.
Silently falling through after a protocol guard mismatchA matching route with mismatched request_protocol is a configuration error.
Logging request bodies for conveniencePrompts, tool arguments, and outputs are private data.