use std::collections::{HashMap, HashSet, VecDeque};
use std::fmt;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use serde_json::Value;
use super::{Error, Result};
const MAX_ACTIVE_STREAMS: usize = 256;
const MAX_COMPLETED_RECEIPTS: usize = 1024;
static NEXT_STREAM_ID: AtomicU64 = AtomicU64::new(0);
struct Cursor {
chunks: Arc<[Value]>,
next_index: usize,
}
#[derive(Default)]
pub(super) struct StreamRegistry {
active: HashMap<String, Cursor>,
completed: HashSet<String>,
completion_order: VecDeque<String>,
}
impl fmt::Debug for StreamRegistry {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("StreamRegistry")
.field("active", &self.active.len())
.field("completed", &self.completed.len())
.field("completion_order", &self.completion_order.len())
.finish()
}
}
fn allocate_id(sequence: &AtomicU64) -> Result<String> {
let previous = sequence
.try_update(Ordering::Relaxed, Ordering::Relaxed, |value| {
value.checked_add(1)
})
.map_err(|_| {
Error::extension("PI_NATIVE_STREAM_LIMIT: native stream identity space exhausted")
})?;
Ok(format!("native-stream-{}", previous + 1))
}
impl StreamRegistry {
pub(super) fn start(&mut self, chunks: Arc<[Value]>) -> Result<String> {
if self.active.len() >= MAX_ACTIVE_STREAMS {
return Err(Error::extension(
"PI_NATIVE_STREAM_LIMIT: too many active native provider streams; finish or cancel an existing stream",
));
}
let id = allocate_id(&NEXT_STREAM_ID)?;
self.active.insert(
id.clone(),
Cursor {
chunks,
next_index: 0,
},
);
Ok(id)
}
pub(super) fn next(&mut self, id: &str) -> Result<Option<Value>> {
if let Some(cursor) = self.active.get_mut(id) {
if let Some(value) = cursor.chunks.get(cursor.next_index) {
let value = value.clone();
cursor.next_index += 1;
return Ok(Some(value));
}
self.active.remove(id);
self.completed.insert(id.to_string());
self.completion_order.push_back(id.to_string());
if self.completion_order.len() > MAX_COMPLETED_RECEIPTS
&& let Some(expired) = self.completion_order.pop_front()
{
self.completed.remove(&expired);
}
return Ok(None);
}
if self.completed.contains(id) {
return Ok(None);
}
Err(Error::extension(
"PI_NATIVE_STREAM_RETIRED: native stream was cancelled, invalidated, or is unknown; it did not report normal exhaustion",
))
}
pub(super) fn cancel(&mut self, id: &str) {
self.active.remove(id);
}
pub(super) fn clear(&mut self) {
self.active.clear();
self.completed.clear();
self.completion_order.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn chunks() -> Arc<[Value]> {
vec![json!("first"), json!("second")].into()
}
#[test]
fn normal_exhaustion_delivers_every_value_and_retains_a_bounded_eof_receipt() {
let mut registry = StreamRegistry::default();
let id = registry.start(chunks()).unwrap();
assert_eq!(registry.next(&id).unwrap(), Some(json!("first")));
assert_eq!(registry.next(&id).unwrap(), Some(json!("second")));
assert!(registry.next(&id).unwrap().is_none());
registry.cancel(&id);
assert!(registry.next(&id).unwrap().is_none());
assert!(registry.active.is_empty());
assert_eq!(registry.completed.len(), 1);
}
#[test]
fn cancellation_and_unknown_handles_are_not_successful_eof() {
let mut registry = StreamRegistry::default();
let id = registry.start(chunks()).unwrap();
registry.next(&id).unwrap();
registry.cancel(&id);
for id in [id.as_str(), "private-forged-handle"] {
let message = registry.next(id).unwrap_err().to_string();
assert!(message.contains("PI_NATIVE_STREAM_RETIRED"));
assert!(!message.contains("private-forged-handle"));
}
}
#[test]
fn cancellation_between_last_value_and_eof_is_not_a_completion() {
let mut registry = StreamRegistry::default();
let id = registry.start(vec![json!("last")].into()).unwrap();
assert_eq!(registry.next(&id).unwrap(), Some(json!("last")));
registry.cancel(&id);
assert!(registry.next(&id).is_err());
assert!(registry.completed.is_empty());
}
#[test]
fn reset_never_reuses_a_handle_or_cancels_a_replacement() {
let mut registry = StreamRegistry::default();
let old = registry.start(chunks()).unwrap();
registry.clear();
let new = registry.start(vec![json!("replacement")].into()).unwrap();
assert_ne!(old, new);
registry.cancel(&old);
assert!(registry.next(&old).is_err());
assert_eq!(registry.next(&new).unwrap(), Some(json!("replacement")));
}
#[test]
fn handles_from_other_runtime_instances_cannot_address_local_streams() {
let mut first = StreamRegistry::default();
let mut second = StreamRegistry::default();
let old = first.start(chunks()).unwrap();
let new = second.start(chunks()).unwrap();
assert_ne!(old, new);
second.cancel(&old);
assert!(second.next(&old).is_err());
assert_eq!(second.next(&new).unwrap(), Some(json!("first")));
}
#[test]
fn live_stream_capacity_never_evicts_accepted_work() {
let mut registry = StreamRegistry::default();
let ids = (0..MAX_ACTIVE_STREAMS)
.map(|_| registry.start(chunks()).unwrap())
.collect::<Vec<_>>();
assert!(
registry
.start(chunks())
.unwrap_err()
.to_string()
.contains("PI_NATIVE_STREAM_LIMIT")
);
for id in &ids {
assert_eq!(registry.next(id).unwrap(), Some(json!("first")));
}
registry.cancel(&ids[0]);
assert!(registry.start(chunks()).is_ok());
}
#[test]
fn completed_receipt_eviction_fails_closed_without_evicting_live_streams() {
let mut registry = StreamRegistry::default();
let live = registry.start(chunks()).unwrap();
let first = registry.start(Vec::new().into()).unwrap();
assert!(registry.next(&first).unwrap().is_none());
for _ in 0..MAX_COMPLETED_RECEIPTS {
let id = registry.start(Vec::new().into()).unwrap();
assert!(registry.next(&id).unwrap().is_none());
}
assert_eq!(registry.completed.len(), MAX_COMPLETED_RECEIPTS);
assert_eq!(registry.completion_order.len(), MAX_COMPLETED_RECEIPTS);
assert!(registry.next(&first).is_err());
assert_eq!(registry.next(&live).unwrap(), Some(json!("first")));
}
#[test]
fn identity_exhaustion_is_an_error_instead_of_aliasing_the_last_stream() {
let sequence = AtomicU64::new(u64::MAX - 1);
assert_eq!(
allocate_id(&sequence).unwrap(),
format!("native-stream-{}", u64::MAX)
);
assert!(allocate_id(&sequence).is_err());
assert!(allocate_id(&sequence).is_err());
assert_eq!(sequence.load(Ordering::Relaxed), u64::MAX);
}
#[test]
fn cancellation_reset_and_completion_release_retained_payloads() {
for action in ["cancel", "clear", "complete"] {
let mut registry = StreamRegistry::default();
let payload = chunks();
let weak = Arc::downgrade(&payload);
let id = registry.start(payload).unwrap();
assert!(weak.upgrade().is_some());
match action {
"cancel" => registry.cancel(&id),
"clear" => registry.clear(),
_ => while registry.next(&id).unwrap().is_some() {},
}
assert!(weak.upgrade().is_none(), "{action}");
}
}
async fn runtime(chunks: Arc<[Value]>) -> super::super::ExtensionRuntimeHandle {
use super::super::{
ExtensionRuntimeHandle, JsExtensionSnapshot, NativeRustExtensionRuntimeHandle,
NativeRustLoadedExtension,
};
let runtime = NativeRustExtensionRuntimeHandle::start().await.unwrap();
runtime
.state
.write()
.unwrap()
.load_extensions(vec![NativeRustLoadedExtension {
snapshot: JsExtensionSnapshot {
id: "fixture".into(),
name: "Fixture".into(),
version: "1".into(),
api_version: "1".into(),
tools: Vec::new(),
slash_commands: Vec::new(),
shortcuts: Vec::new(),
providers: Vec::new(),
mcp_servers: Vec::new(),
flags: Vec::new(),
event_hooks: Vec::new(),
active_tools: None,
},
event_responses: HashMap::new(),
tool_outputs: HashMap::new(),
command_outputs: HashMap::new(),
shortcut_outputs: HashMap::new(),
provider_streams: HashMap::from([("fixture".to_string(), chunks)]),
}]);
ExtensionRuntimeHandle::NativeRust(runtime)
}
async fn start(runtime: &super::super::ExtensionRuntimeHandle) -> String {
runtime
.provider_stream_simple_start(
"fixture".into(),
Value::Null,
Value::Null,
Value::Null,
1000,
)
.await
.unwrap()
}
#[test]
fn public_runtime_reset_retires_streams_without_affecting_the_next_request() {
futures::executor::block_on(async {
let runtime = runtime(chunks()).await;
let old = start(&runtime).await;
assert_eq!(
runtime
.provider_stream_simple_next(old.clone(), 1000)
.await
.unwrap(),
Some(json!("first"))
);
runtime.reset_transient_state().await.unwrap();
let new = start(&runtime).await;
runtime.provider_stream_simple_cancel_best_effort(old.clone());
assert!(
runtime
.provider_stream_simple_next(old, 1000)
.await
.is_err()
);
assert_eq!(
runtime
.provider_stream_simple_next(new, 1000)
.await
.unwrap(),
Some(json!("first"))
);
});
}
#[test]
fn descriptor_replacement_cannot_rebind_an_old_stream_identity() {
futures::executor::block_on(async {
let runtime = runtime(chunks()).await;
let old = start(&runtime).await;
let super::super::ExtensionRuntimeHandle::NativeRust(native) = &runtime else {
unreachable!()
};
{
let mut state = native.state.write().unwrap();
let mut replacement = state.extensions.clone();
replacement[0]
.provider_streams
.insert("fixture".into(), vec![json!("new")].into());
state.load_extensions(replacement);
}
let new = start(&runtime).await;
assert_ne!(old, new);
runtime
.provider_stream_simple_cancel(old.clone(), 1000)
.await
.unwrap();
assert!(
runtime
.provider_stream_simple_next(old, 1000)
.await
.is_err()
);
assert_eq!(
runtime
.provider_stream_simple_next(new, 1000)
.await
.unwrap(),
Some(json!("new"))
);
});
}
#[test]
fn runtime_cancellation_after_last_chunk_does_not_manufacture_success() {
futures::executor::block_on(async {
let runtime = runtime(vec![json!("partial")].into()).await;
let id = start(&runtime).await;
runtime
.provider_stream_simple_next(id.clone(), 1000)
.await
.unwrap();
runtime
.provider_stream_simple_cancel(id.clone(), 1000)
.await
.unwrap();
assert!(runtime.provider_stream_simple_next(id, 1000).await.is_err());
let completed = start(&runtime).await;
runtime
.provider_stream_simple_next(completed.clone(), 1000)
.await
.unwrap();
assert!(
runtime
.provider_stream_simple_next(completed.clone(), 1000)
.await
.unwrap()
.is_none()
);
assert!(
runtime
.provider_stream_simple_next(completed, 1000)
.await
.unwrap()
.is_none()
);
});
}
}