pub trait Channel: Send + Sync {
Show 24 methods
// Required methods
fn id(&self) -> &'static str;
fn routing_table(&self) -> RouteList;
fn prepare(
&self,
ctx: PrepareCtx<'_>,
) -> Result<PreparedRequest, ChannelError>;
// Provided methods
fn metadata(&self) -> ChannelMetadata { ... }
fn classify(
&self,
status: StatusCode,
headers: &HeaderMap,
_body: &Bytes,
) -> Disposition { ... }
fn credential_wide_auth(&self) -> bool { ... }
fn cookie_login_requires_browser(&self) -> bool { ... }
fn refresh_requires_browser(&self, _secret: &Value) -> bool { ... }
fn shares_account_quota(&self, _upstream_model_id: &str) -> bool { ... }
fn shape_request(
&self,
body: Bytes,
_headers: &mut HeaderMap,
_ctx: &ShapeCtx<'_>,
) -> Bytes { ... }
fn shape_response(&self, body: Bytes, _ctx: &ShapeCtx<'_>) -> Bytes { ... }
fn bundled_models(&self) -> Option<ModelCatalog> { ... }
fn credential_models(&self, _secret: &Value) -> Option<ModelCatalog> { ... }
fn stream_decoder(&self) -> Option<Box<dyn ChannelStreamDecoder>> { ... }
fn needs_refresh(&self, _secret: &Value) -> bool { ... }
fn refresh<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_client: &'life1 Arc<dyn UpstreamClient>,
_ctx: RefreshCtx<'life2>,
) -> Pin<Box<dyn Future<Output = Result<Value, ChannelError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn transport(&self) -> TransportKind { ... }
fn prepare_credential_control_request(
&self,
operation: &CredentialControlOperation,
secret: &Value,
settings: &Value,
) -> Result<Option<Request<Bytes>>, ChannelError> { ... }
fn parse_credential_control_response(
&self,
operation: &CredentialControlOperation,
status: StatusCode,
headers: &HeaderMap,
body: &Bytes,
) -> Option<CredentialControlResponse> { ... }
fn prepare_usage_request(
&self,
_secret: &Value,
_settings: &Value,
) -> Result<Option<Request<Bytes>>, ChannelError> { ... }
fn parse_usage(
&self,
_status: StatusCode,
_headers: &HeaderMap,
_body: &Bytes,
) -> Option<UsageSnapshot> { ... }
fn describe_usage_window(
&self,
snapshot: &UsageSnapshot,
index: usize,
) -> UsageWindowDescriptor { ... }
fn prepare_rate_limit_reset_credit_request(
&self,
_secret: &Value,
_settings: &Value,
_idempotency_key: &str,
) -> Result<Option<Request<Bytes>>, ChannelError> { ... }
fn parse_rate_limit_reset_credit(
&self,
_status: StatusCode,
_headers: &HeaderMap,
_body: &Bytes,
) -> Option<RateLimitResetCreditConsumeResponse> { ... }
}Expand description
Pure upstream access adapter (§6.3). Implementors provide id,
routing_table and prepare; the rest have sensible defaults.
Required Methods§
Sourcefn id(&self) -> &'static str
fn id(&self) -> &'static str
Stable channel id used as the registry key (matches Provider.channel).
Sourcefn routing_table(&self) -> RouteList
fn routing_table(&self) -> RouteList
The channel’s explicit routing surface (ported from its capabilities).
Sourcefn prepare(&self, ctx: PrepareCtx<'_>) -> Result<PreparedRequest, ChannelError>
fn prepare(&self, ctx: PrepareCtx<'_>) -> Result<PreparedRequest, ChannelError>
Inject auth, resolve endpoint + method, set an ABSOLUTE upstream URL.
Pure access — no transform/rules, no body mutation. Moves ctx.body in.
Provided Methods§
Sourcefn metadata(&self) -> ChannelMetadata
fn metadata(&self) -> ChannelMetadata
Metadata for runtime discovery and generic configuration UIs.
Sourcefn classify(
&self,
status: StatusCode,
headers: &HeaderMap,
_body: &Bytes,
) -> Disposition
fn classify( &self, status: StatusCode, headers: &HeaderMap, _body: &Bytes, ) -> Disposition
Map an upstream response to the 5-state Disposition. Default is the
generic HTTP-status mapping; override only for provider-specific signals.
For streaming, body is empty (status + headers suffice).
Sourcefn credential_wide_auth(&self) -> bool
fn credential_wide_auth(&self) -> bool
Whether a model-bound auth rejection (401/402/403) kills the WHOLE
credential rather than only the exact (credential, model) pair. true
for subscription-account channels (codex, claudecode) whose token is
account-wide. Default: model-scoped.
Whether first-time cookie exchange must use the native browser profile.
Sourcefn refresh_requires_browser(&self, _secret: &Value) -> bool
fn refresh_requires_browser(&self, _secret: &Value) -> bool
Whether refreshing this secret must use the native browser profile.
Whether this model draws from the channel’s account-wide MAIN quota
pool. The main limit governs the whole account, so a 429 here cools the
WHOLE credential (separate-limit models included). Models with an
ADDITIONAL scoped limit on top of the main pool (codex spark, claude
fable) return false: their own 429 means only the scoped limit is hit
and stays model-scoped. Default: false (per-model quota, api-key
channels).
Sourcefn shape_request(
&self,
body: Bytes,
_headers: &mut HeaderMap,
_ctx: &ShapeCtx<'_>,
) -> Bytes
fn shape_request( &self, body: Bytes, _headers: &mut HeaderMap, _ctx: &ShapeCtx<'_>, ) -> Bytes
Channel-specific REQUEST-body shaping (整形): runs after protocol
transform + process rules, before prepare. Pure
field hygiene (strip unsupported fields, cap/rename, role/tools
normalize, remove header tokens). Default: identity.
Sourcefn shape_response(&self, body: Bytes, _ctx: &ShapeCtx<'_>) -> Bytes
fn shape_response(&self, body: Bytes, _ctx: &ShapeCtx<'_>) -> Bytes
Channel-specific RESPONSE-body shaping (整形) on the raw buffered upstream
body, before protocol transform. Operation-aware via ctx so a channel
can reshape model lists, fix non-standard fields, unwrap envelopes, etc.
Runs on ALL statuses (error bodies included). Default: identity.
Sourcefn bundled_models(&self) -> Option<ModelCatalog>
fn bundled_models(&self) -> Option<ModelCatalog>
A channel-bundled static model catalogue, for channels whose upstream
exposes no model-list endpoint (e.g. vertexexpress). When Some, the
admin model-pull returns it directly — no credential / upstream call. The
returned catalogue identifies its own canonical model-list wire family.
Default: none.
Sourcefn credential_models(&self, _secret: &Value) -> Option<ModelCatalog>
fn credential_models(&self, _secret: &Value) -> Option<ModelCatalog>
A credential-scoped model catalogue discovered while authenticating or
refreshing the secret. Unlike bundled_models,
this hook is evaluated only after the credential has been decrypted and
refreshed, so account-specific catalogues can be returned without an
extra upstream model-list request. Default: none.
Sourcefn stream_decoder(&self) -> Option<Box<dyn ChannelStreamDecoder>>
fn stream_decoder(&self) -> Option<Box<dyn ChannelStreamDecoder>>
Optional channel-specific stream decoder (envelope unwrap / binary → SSE), applied to the raw upstream byte stream before any protocol transform. Default: none (passthrough).
Sourcefn needs_refresh(&self, _secret: &Value) -> bool
fn needs_refresh(&self, _secret: &Value) -> bool
Whether the DECRYPTED secret must be refreshed before use (e.g. OAuth access token near expiry). Default: never.
Sourcefn refresh<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_client: &'life1 Arc<dyn UpstreamClient>,
_ctx: RefreshCtx<'life2>,
) -> Pin<Box<dyn Future<Output = Result<Value, ChannelError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn refresh<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_client: &'life1 Arc<dyn UpstreamClient>,
_ctx: RefreshCtx<'life2>,
) -> Pin<Box<dyn Future<Output = Result<Value, ChannelError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Refresh the credential against the provider, returning the new PLAINTEXT secret Value. The pipeline re-seals + persists + publishes — the channel never touches cipher/persistence (purity §6.3). Default: unsupported.
fn transport(&self) -> TransportKind
Sourcefn prepare_credential_control_request(
&self,
operation: &CredentialControlOperation,
secret: &Value,
settings: &Value,
) -> Result<Option<Request<Bytes>>, ChannelError>
fn prepare_credential_control_request( &self, operation: &CredentialControlOperation, secret: &Value, settings: &Value, ) -> Result<Option<Request<Bytes>>, ChannelError>
Build one credential-scoped account/control request. The default bridges the two legacy usage/reset hooks so existing channels keep working; new account operations opt in explicitly per channel.
Sourcefn parse_credential_control_response(
&self,
operation: &CredentialControlOperation,
status: StatusCode,
headers: &HeaderMap,
body: &Bytes,
) -> Option<CredentialControlResponse>
fn parse_credential_control_response( &self, operation: &CredentialControlOperation, status: StatusCode, headers: &HeaderMap, body: &Bytes, ) -> Option<CredentialControlResponse>
Parse a response to [prepare_credential_control_request].
Sourcefn prepare_usage_request(
&self,
_secret: &Value,
_settings: &Value,
) -> Result<Option<Request<Bytes>>, ChannelError>
fn prepare_usage_request( &self, _secret: &Value, _settings: &Value, ) -> Result<Option<Request<Bytes>>, ChannelError>
Build a request to this channel’s per-credential upstream usage / quota
endpoint, given an already-fresh decrypted secret and provider
settings. None (the default) means the channel exposes no usage
endpoint (api-key / vertex channels). The driver sends it through the
credential’s resolved client (same proxy + TLS profile as traffic) and
feeds the response to parse_usage. Pure access:
no persistence, no body shaping beyond what the endpoint needs.
Sourcefn parse_usage(
&self,
_status: StatusCode,
_headers: &HeaderMap,
_body: &Bytes,
) -> Option<UsageSnapshot>
fn parse_usage( &self, _status: StatusCode, _headers: &HeaderMap, _body: &Bytes, ) -> Option<UsageSnapshot>
Parse this channel’s usage-endpoint response into the normalized
UsageSnapshot. Called only with the response to the request from
prepare_usage_request. None on a
non-success status or an unparseable body.
Sourcefn describe_usage_window(
&self,
snapshot: &UsageSnapshot,
index: usize,
) -> UsageWindowDescriptor
fn describe_usage_window( &self, snapshot: &UsageSnapshot, index: usize, ) -> UsageWindowDescriptor
Describe the stable identity, scope, meter and period boundary of one
normalized usage window. The host calls this only with an index from
snapshot.windows; the conservative default keeps existing external
channel implementations source-compatible.
Sourcefn prepare_rate_limit_reset_credit_request(
&self,
_secret: &Value,
_settings: &Value,
_idempotency_key: &str,
) -> Result<Option<Request<Bytes>>, ChannelError>
fn prepare_rate_limit_reset_credit_request( &self, _secret: &Value, _settings: &Value, _idempotency_key: &str, ) -> Result<Option<Request<Bytes>>, ChannelError>
Build a request to consume one earned rate-limit reset credit. Only channels whose upstream exposes this account action return a request.
Sourcefn parse_rate_limit_reset_credit(
&self,
_status: StatusCode,
_headers: &HeaderMap,
_body: &Bytes,
) -> Option<RateLimitResetCreditConsumeResponse>
fn parse_rate_limit_reset_credit( &self, _status: StatusCode, _headers: &HeaderMap, _body: &Bytes, ) -> Option<RateLimitResetCreditConsumeResponse>
Parse the response from
prepare_rate_limit_reset_credit_request.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".