Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions crates/native-sidecar-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,9 @@ pub use root_fs::{
root_snapshot_from_entries, SidecarCoreError,
};
pub use router::{
connection_id_of, generated_wire_blocking_extension_interrupt, request_dispatch_mode,
request_is_unsupported_host_callback_direction, route_request_payload, session_scope_of,
unsupported_host_callback_direction_dispatch, vm_id_of, BlockingExtensionInterrupt,
RequestDispatchMode, RequestRoute, UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE,
connection_id_of, request_dispatch_mode, request_is_unsupported_host_callback_direction,
route_request_payload, session_scope_of, unsupported_host_callback_direction_dispatch,
vm_id_of, RequestDispatchMode, RequestRoute, UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE,
UNSUPPORTED_HOST_CALLBACK_DIRECTION_MESSAGE,
};
pub use signals::{
Expand Down
123 changes: 0 additions & 123 deletions crates/native-sidecar-core/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use agentos_sidecar_protocol::protocol::{
RequestFrame, RequestPayload, ResizePtyRequest, SealLayerRequest,
SnapshotRootFilesystemRequest, VmFetchRequest, WriteStdinRequest,
};
use agentos_sidecar_protocol::wire as generated_wire;

pub const UNSUPPORTED_HOST_CALLBACK_DIRECTION_CODE: &str = "unsupported_direction";
pub const UNSUPPORTED_HOST_CALLBACK_DIRECTION_MESSAGE: &str =
Expand Down Expand Up @@ -63,12 +62,6 @@ pub enum RequestRoute {
UnsupportedHostCallbackDirection,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlockingExtensionInterrupt<'a> {
ExtensionPayload(&'a [u8]),
KillProcess,
}

pub fn route_request_payload(request: &RequestFrame) -> RequestRoute {
match request.payload.clone() {
RequestPayload::Authenticate(payload) => RequestRoute::Authenticate(payload),
Expand Down Expand Up @@ -145,31 +138,6 @@ pub fn route_request_payload(request: &RequestFrame) -> RequestRoute {
}
}

pub fn generated_wire_blocking_extension_interrupt<'a>(
active_request: &generated_wire::RequestFrame,
blocking_namespace: &str,
interrupting_request: &'a generated_wire::RequestFrame,
) -> Option<BlockingExtensionInterrupt<'a>> {
if interrupting_request.ownership != active_request.ownership {
return None;
}

match &interrupting_request.payload {
generated_wire::RequestPayload::ExtEnvelope(envelope)
if envelope.namespace == blocking_namespace =>
{
Some(BlockingExtensionInterrupt::ExtensionPayload(
&envelope.payload,
))
}
generated_wire::RequestPayload::ExtEnvelope(_) => None,
generated_wire::RequestPayload::KillProcessRequest(_) => {
Some(BlockingExtensionInterrupt::KillProcess)
}
_ => None,
}
}

pub fn request_dispatch_mode(request: &RequestFrame) -> RequestDispatchMode {
match request.payload {
RequestPayload::DisposeVm(_) | RequestPayload::Ext(_) => RequestDispatchMode::Async,
Expand Down Expand Up @@ -297,25 +265,11 @@ mod tests {
OwnershipScope, PersistenceFlushRequest, PersistenceLoadRequest, ResponsePayload,
PROTOCOL_VERSION,
};
use agentos_sidecar_protocol::wire as generated_wire;

fn request(payload: RequestPayload) -> RequestFrame {
RequestFrame::new(7, OwnershipScope::connection("conn"), payload)
}

fn generated_request(
request_id: i64,
ownership: generated_wire::OwnershipScope,
payload: generated_wire::RequestPayload,
) -> generated_wire::RequestFrame {
generated_wire::RequestFrame {
schema: generated_wire::protocol_schema(),
request_id,
ownership,
payload,
}
}

fn reverse_host_callback_payloads() -> Vec<RequestPayload> {
vec![
RequestPayload::HostFilesystemCall(HostFilesystemCallRequest {
Expand Down Expand Up @@ -423,83 +377,6 @@ mod tests {
}
}

#[test]
fn generated_wire_prompt_interrupt_classifier_matches_only_same_scope_interrupts() {
let ownership = generated_wire::OwnershipScope::VmOwnership(generated_wire::VmOwnership {
connection_id: String::from("conn"),
session_id: String::from("session"),
vm_id: String::from("vm"),
});
let active = generated_request(
1,
ownership.clone(),
generated_wire::RequestPayload::ExtEnvelope(generated_wire::ExtEnvelope {
namespace: String::from("prompt"),
payload: b"active".to_vec(),
}),
);

let same_namespace = generated_request(
2,
ownership.clone(),
generated_wire::RequestPayload::ExtEnvelope(generated_wire::ExtEnvelope {
namespace: String::from("prompt"),
payload: b"cancel".to_vec(),
}),
);
assert_eq!(
generated_wire_blocking_extension_interrupt(&active, "prompt", &same_namespace),
Some(BlockingExtensionInterrupt::ExtensionPayload(b"cancel"))
);

let kill = generated_request(
3,
ownership.clone(),
generated_wire::RequestPayload::KillProcessRequest(
generated_wire::KillProcessRequest {
process_id: String::from("proc"),
signal: String::from("SIGTERM"),
},
),
);
assert_eq!(
generated_wire_blocking_extension_interrupt(&active, "prompt", &kill),
Some(BlockingExtensionInterrupt::KillProcess)
);

let other_namespace = generated_request(
4,
ownership.clone(),
generated_wire::RequestPayload::ExtEnvelope(generated_wire::ExtEnvelope {
namespace: String::from("other"),
payload: b"cancel".to_vec(),
}),
);
assert_eq!(
generated_wire_blocking_extension_interrupt(&active, "prompt", &other_namespace),
None
);

let other_scope = generated_request(
5,
generated_wire::OwnershipScope::VmOwnership(generated_wire::VmOwnership {
connection_id: String::from("conn"),
session_id: String::from("session"),
vm_id: String::from("other-vm"),
}),
generated_wire::RequestPayload::KillProcessRequest(
generated_wire::KillProcessRequest {
process_id: String::from("proc"),
signal: String::from("SIGTERM"),
},
),
);
assert_eq!(
generated_wire_blocking_extension_interrupt(&active, "prompt", &other_scope),
None
);
}

#[test]
fn ownership_scope_helpers_extract_shared_ids() {
let connection = OwnershipScope::connection("conn-1");
Expand Down
2 changes: 1 addition & 1 deletion crates/native-sidecar/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Migration status: **resource limits** (typed `*ExecutionLimits` on the execution
- `RequestPayload::Ext`, `ResponsePayload::ExtResult`, `EventPayload::Ext`, and sidecar callback `Ext` payloads are opaque to core sidecar code; dispatch only by namespace and leave inner payload decoding to the registered extension.
- `ExtensionContext` primitives should delegate to existing `NativeSidecar` ownership, process, event, and callback paths instead of giving extensions direct access to internal maps such as VM tables or ACP session state.
- Extension callbacks and events must stay transport-agnostic: do not expose stdio, socket, or browser `postMessage` details through the `Extension` trait or `ExtensionContext`.
- Stdio blocking-request interruption must stay extension-owned. Core stdio may call generic `Extension` hooks, but production agentos-native-sidecar code must not decode ACP payloads or depend on `agentos-protocol`.
- Progress classification must stay extension-owned and opaque. Core stdio may call the generic `Extension::request_class` hook, but production native-sidecar code must not decode ACP payloads, depend on `agentos-protocol`, or reintroduce prompt-specific interruption hooks/pending-frame slots.
- Sidecar-to-host callback protocol must stay agent-agnostic: use `HostCallback{callback_key}` for generic host callbacks, and keep binding collection-specific naming and schemas out of the core callback frame.
- Legacy ACP helpers under `tests/acp_legacy/` are fixtures only; production ACP behavior belongs in `crates/agentos-sidecar`, not `crates/sidecar/src`.
- Binding CLI `--json` and `--json-file` payloads in `src/bindings.rs` must be validated against the registered host callback `input_schema` before building `HostCallbackRequest`; relying on the host callback to fail closed leaves non-TypeScript hosts and any pre-dispatch checks exposed to raw, unvalidated payload shapes.
Expand Down
31 changes: 0 additions & 31 deletions crates/native-sidecar/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,25 +849,6 @@ pub enum ExtensionOrderingPolicy {
ExtensionManaged,
}

/// Compatibility input for the legacy blocking-extension stdio path. The
/// routed protocol engine no longer uses this hook; it remains present only in
/// the lower ownership-partition revision until that caller is removed later
/// in the stack.
pub enum ExtensionInterruptRequest<'a> {
ExtensionPayload {
payload: &'a [u8],
ownership: &'a OwnershipScope,
},
KillProcess,
}

#[derive(Debug, Clone)]
pub struct ExtensionInterruptResponse {
pub interrupt_active: bool,
pub interrupted_response_payload: Vec<u8>,
pub interrupting_response_payload: Option<Vec<u8>>,
}

pub trait Extension: Send + Sync {
fn namespace(&self) -> &str;

Expand Down Expand Up @@ -930,18 +911,6 @@ pub trait Extension: Send + Sync {
Box::pin(async { Ok(()) })
}

fn is_blocking_request(&self, _payload: &[u8]) -> bool {
false
}

fn interrupt_blocking_request(
&self,
_blocking_payload: &[u8],
_interrupt: ExtensionInterruptRequest<'_>,
) -> Option<ExtensionInterruptResponse> {
None
}

fn on_dispose<'a>(&'a self) -> ExtensionFuture<'a, ()> {
Box::pin(async { Ok(()) })
}
Expand Down
4 changes: 2 additions & 2 deletions crates/native-sidecar/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ pub mod vm_sqlite;
pub use agentos_sidecar_protocol::{generated_protocol, protocol, wire};

pub use extension::{
Extension, ExtensionContext, ExtensionFuture, ExtensionInterruptRequest,
ExtensionInterruptResponse, ExtensionOrderingPolicy, ExtensionRequestClass, ExtensionResponse,
Extension, ExtensionContext, ExtensionFuture, ExtensionOrderingPolicy, ExtensionRequestClass,
ExtensionResponse,
};
pub use service::{DispatchResult, NativeSidecar, NativeSidecarConfig, SidecarError};
pub use state::EventSinkTransport;
Expand Down
Loading