pub struct RequestContext { /* private fields */ }Expand description
Everything a handler is allowed to know about the call it is serving.
Implementations§
Source§impl RequestContext
impl RequestContext
Sourcepub fn for_request(
peer: &PeerSession,
id: RequestId,
cancel: CancellationToken,
progress: Option<ProgressToken>,
) -> Self
pub fn for_request( peer: &PeerSession, id: RequestId, cancel: CancellationToken, progress: Option<ProgressToken>, ) -> Self
Binds one in-flight request to the connection serving it.
Clones the session, which is two Arc bumps and two Copy fields. That
is why a server with a thousand in-flight requests pays a thousand
pointer bumps rather than a thousand deep copies of the profile.
The state map is empty. A test that needs state should use
for_request_with_state; a
production handler gets the map from the Server it was
built with.
Sourcepub fn for_request_with_state(
peer: &PeerSession,
id: RequestId,
cancel: CancellationToken,
progress: Option<ProgressToken>,
state: Arc<StateMap>,
) -> Self
pub fn for_request_with_state( peer: &PeerSession, id: RequestId, cancel: CancellationToken, progress: Option<ProgressToken>, state: Arc<StateMap>, ) -> Self
Binds one in-flight request to the connection serving it, with the server’s registered state.
The state map is the one the
Server accumulated
through with_state calls. The context holds an Arc
rather than the values, so a thousand concurrent requests
share one allocation rather than each deep-copying the
database pool.
Sourcepub fn input_response(&self, key: &str) -> Option<JsonObject>
pub fn input_response(&self, key: &str) -> Option<JsonObject>
The client’s answer to the input request filed under key.
None on a first round, and on a retry that did not answer that key —
which a handler should treat as “ask again” rather than as an error,
because SEP-2322 has the server re-request what is missing.
Sourcepub const fn has_input_responses(&self) -> bool
pub const fn has_input_responses(&self) -> bool
Whether this request is a retry carrying inputResponses at all.
Sourcepub fn request_state(&self) -> Option<&str>
pub fn request_state(&self) -> Option<&str>
The requestState this server sealed on the previous round.
Already verified: a state that did not open was refused before the handler ran, so anything returned here is the server’s own.
Sourcepub fn seal_state(&self, state: &str) -> Result<String, GatedError>
pub fn seal_state(&self, state: &str) -> Result<String, GatedError>
Seals state for an InputRequired result’s requestState.
§Errors
GatedError::NoStateKey when the server was built without a key and
no transport supplied one, so there is nothing to seal under.
Sourcepub fn state<T: Send + Sync + 'static>(&self) -> Option<&T>
pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T>
Looks up a state value by its concrete type.
The state map is keyed by TypeId, and the value is stored as
Arc<dyn Any>, so the lookup is two HashMap operations and one
downcast. The Send + Sync bounds are the same the
Server::with_state
builder requires, so a T registered here is reachable here.
Returns None for a type that was never registered. That is
the right answer for a state the handler treats as optional;
a handler that requires a piece of state should .expect
the result with a message naming the missing type, or it
should be registered at server construction.
§Examples
#[tool]
async fn search(ctx: RequestContext, query: String) -> Result<JsonObject, ToolError> {
let db = ctx.state::<MyPool>().expect("MyPool was registered");
db.search(query).await
}Sourcepub const fn peer(&self) -> &PeerSession
pub const fn peer(&self) -> &PeerSession
The connection serving this request.
Sourcepub const fn request_id(&self) -> &RequestId
pub const fn request_id(&self) -> &RequestId
The request id, for correlating anything the handler emits itself.
Sourcepub const fn cancellation(&self) -> &CancellationToken
pub const fn cancellation(&self) -> &CancellationToken
The caller’s cancellation token, so a long handler can observe it.
Sourcepub const fn progress_token(&self) -> Option<&ProgressToken>
pub const fn progress_token(&self) -> Option<&ProgressToken>
The progress token the client opened, if it opened one.
Sourcepub async fn elicit(
&self,
params: &JsonObject,
) -> Result<JsonObject, GatedError>
pub async fn elicit( &self, params: &JsonObject, ) -> Result<JsonObject, GatedError>
Asks the peer for extra input from the user.
Gated on Feature::Elicitation. The gate runs first, so a session
that never negotiated it writes nothing at all — see
GatedError::wrote_nothing.
§Errors
GatedError::FeatureUnavailable when elicitation was not negotiated,
having written nothing. GatedError::MalformedAnswer when the
exchange did not complete, which is the one case here where the request
did reach the wire first.
Sourcepub async fn sample(
&self,
params: &JsonObject,
) -> Result<JsonObject, GatedError>
pub async fn sample( &self, params: &JsonObject, ) -> Result<JsonObject, GatedError>
Asks the peer to run a model on the server’s behalf.
Gated on Feature::Sampling, on the same terms as InputRequired::elicit.
§Errors
Sourcepub async fn create_task(
&self,
params: &JsonObject,
) -> Result<JsonObject, GatedError>
pub async fn create_task( &self, params: &JsonObject, ) -> Result<JsonObject, GatedError>
Opens a long-running task for this request.
Gated on Feature::Tasks, which enters the core protocol in
2025-11-25 and moves to an extension in 2026-07-28 — so the same
call is available, unavailable, and available-elsewhere across three
revisions, and the gate is what makes that legible.
§Errors
Sourcepub async fn report_progress(
&self,
params: &JsonObject,
) -> Result<(), GatedError>
pub async fn report_progress( &self, params: &JsonObject, ) -> Result<(), GatedError>
Reports progress on a request the client opened a channel for.
Not feature-gated, and deliberately: progress is core to every revision
from 2024-11-05 onward, so a Feature for it would be a fiction.
What can be absent is the token — the client chose whether to open
the channel, and a report without one has nowhere to go.
§Errors
GatedError::NoProgressToken when the client did not open a progress
channel for this request, having written nothing.
Sourcepub async fn log(
&self,
level: LogLevel,
message: &str,
) -> Result<(), GatedError>
pub async fn log( &self, level: LogLevel, message: &str, ) -> Result<(), GatedError>
Emits a notifications/message log record.
The fourth of the server-side channels a handler can open, alongside progress, sampling and elicitation, and the only one that needs no token from the caller: a log record is addressed to the peer as a whole rather than to a request, so there is nothing to correlate it against. That is what makes it the odd one out here — every other gated operation has a precondition the peer establishes first, and this one has none.
Gated on Feature::Logging, and like the other gates it runs before
anything is written, so a session that never negotiated logging emits
nothing at all rather than a record the peer will ignore.
§Errors
GatedError::FeatureUnavailable when logging was not negotiated,
having written nothing. GatedError::MalformedAnswer when the
notification did not reach the peer.
Trait Implementations§
Source§impl Clone for RequestContext
impl Clone for RequestContext
Source§impl Debug for RequestContext
impl Debug for RequestContext
Source§fn fmt(&self, f: &mut Formatter<'_>) -> Result
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Prints what a post-mortem needs and nothing else.
Handwritten because the derived form would print the request id in
full, and a request id in a log line is exactly what the redaction rule
exists to prevent. The id goes through RequestId::redacted.