1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! CEP-22: progress-aware request options for rmcp consumers.
//!
//! Under the rmcp fork, plain [`Peer`] calls such as `call_tool` use
//! `PeerRequestOptions::no_options()` — **no timeout at all**: a stalled
//! oversized response hangs the caller forever. This module closes that gap
//! the way the TS SDK's docs do — by passing request options on the existing
//! call — via an extension trait carrying an options-taking `call_tool`
//! variant, plus a constructor for the recommended progress-aware settings.
//!
//! With CEP-22 enabled, the Nostr transports forward each inbound transfer
//! frame to the requester as a plain progress notification, so an idle
//! timeout built by [`progress_aware_options`] resets on every chunk: a live
//! transfer can run long, a stalled one fails after `idle`, and
//! `max_total` caps the call regardless of progress.
//!
//! ```ignore
//! use contextvm_sdk::{progress_aware_options, PeerRequestOptionsExt};
//!
//! let result = running_service
//! .peer()
//! .call_tool_with_options(
//! params,
//! progress_aware_options(
//! contextvm_sdk::DEFAULT_OVERSIZED_IDLE_TIMEOUT,
//! contextvm_sdk::DEFAULT_OVERSIZED_MAX_TOTAL_TIMEOUT,
//! ),
//! )
//! .await?;
//! ```
use Duration;
use ;
use ;
use RoleClient;
/// Default requester-side idle timeout for requests that may trigger a CEP-22
/// oversized transfer: 60 s.
///
/// TS parity twice over: equals the upstream TS SDK's blanket per-request
/// timeout (`DEFAULT_REQUEST_TIMEOUT_MSEC`), and exceeds the worst-case
/// inter-chunk gap including the 30 s accept wait
/// ([`DEFAULT_ACCEPT_TIMEOUT_MS`](crate::transport::oversized_transfer::DEFAULT_ACCEPT_TIMEOUT_MS)).
pub const DEFAULT_OVERSIZED_IDLE_TIMEOUT: Duration = from_secs;
/// Default requester-side max-total timeout: 300 s.
///
/// Aligned with the receiver-side watchdog default
/// ([`DEFAULT_TRANSFER_TIMEOUT_MS`](crate::transport::oversized_transfer::DEFAULT_TRANSFER_TIMEOUT_MS))
/// so the requester gives up in the same window the receiver reaps state —
/// symmetric failure. (Upstream TS sets no max-total default; here it stays
/// opt-in via [`progress_aware_options`], never baked into plain calls.)
pub const DEFAULT_OVERSIZED_MAX_TOTAL_TIMEOUT: Duration = from_secs;
/// Build the recommended [`PeerRequestOptions`] for requests whose responses
/// may arrive as CEP-22 oversized transfers: an `idle` timeout that resets on
/// every progress notification, capped by `max_total`.
///
/// Equivalent to
/// `PeerRequestOptions::with_timeout(idle).reset_timeout_on_progress().with_max_total_timeout(max_total)`.
/// Named after the mechanism (progress-aware timeouts), not the oversized use
/// case — mirroring the TS SDK, where "oversized" appears in docs but never in
/// the API surface.
///
/// Sizing notes:
/// - `reset_timeout_on_progress` without an idle timeout is a **no-op** — the
/// fork registers a progress watcher only when *both* are set, which is why
/// this constructor takes `idle` rather than making it optional.
/// - The client→server upload direction receives at most **one** inbound
/// reset (the server's `accept` handshake frame) — and it reaches the rmcp
/// service loop only after the whole upload send returns. Size `idle` and
/// `max_total` to cover the full upload duration, not just the gaps.
/// - Sensible defaults: [`DEFAULT_OVERSIZED_IDLE_TIMEOUT`] /
/// [`DEFAULT_OVERSIZED_MAX_TOTAL_TIMEOUT`]. They intentionally mirror the
/// transport's `OversizedTransferConfig` numbers but are not read from it —
/// the peer layer has no access to transport config by design; align them
/// manually if you tune the transport.
/// Options-taking call variants for [`Peer<RoleClient>`] — the rs-side analog
/// of passing `RequestOptions` inline to the TS SDK's `client.callTool`.
///
/// Without these, high-level fork calls (`peer.call_tool(..)` etc.) run with
/// `PeerRequestOptions::no_options()`: **no timeout, infinite await**. Pair
/// with [`progress_aware_options`] for any call whose response may be large
/// (CEP-22 fragments every rmcp request's response once the peer advertises
/// support — rmcp stamps a progress token into every outgoing request).
///
/// For request types without a dedicated variant here, the generic path is
/// two lines on public fork API — no wrapper needed:
///
/// ```ignore
/// let handle = peer.send_cancellable_request(request, options).await?;
/// let response = handle.await_response().await?;
/// ```
///
/// On timeout the call fails with `ServiceError::Timeout { timeout }` (the
/// value identifies which timer fired: `idle` vs `max_total`) and rmcp
/// publishes a `notifications/cancelled` for the request.