Skip to main content

HarnessSessionService

Struct HarnessSessionService 

Source
pub struct HarnessSessionService { /* private fields */ }
Expand description

Stateful persisted-session service. Each instance owns its follow subscriptions; discovery and loading remain read-only.

Implementations§

Source§

impl HarnessSessionService

Source

pub fn new() -> Self

Create an empty service instance.

Source

pub fn with_reduction_store_root(self, root: impl Into<PathBuf>) -> Self

Override the trusted, service-owned store used for durable reduction bundles. Embedders and tests use this to keep all writes inside an explicitly selected root; the CLI otherwise uses the normal $SUPERCODE_HOME/sessions location.

Source

pub fn observe_subagent_approvals( &mut self, queue: Arc<Mutex<Vec<QueuedApproval>>>, )

ORCH-9: publish the parent’s own subagent-approval queue into harness.v1.approvals.list.

This is the SAME Arc an crate::Agent pushes into (Agent::pending_child_approvals), so a host that runs supercode’s own loop beside this service surfaces those requests through the uniform door without copying them anywhere.

Source

pub fn approvals(&self, query: &ApprovalsQuery) -> Vec<ApprovalRow>

ORCH-9: every approval request this service can see, newest last.

Two sources, both live: the requests outstanding on the open runtime connections, and supercode’s own queued subagent approvals. There is no file or database source at the pinned harness versions (see crate::approvals), so a stored or proposal row is never produced.

Source

pub fn session_index_notifier(&self) -> Arc<Notify>

Return the edge-triggered wakeup used by session-index filesystem subscriptions. Transports can await this instead of polling indexes.

Source

pub fn handle(&mut self, request: Value) -> Value

Handle one JSON-RPC 2.0 request and return one JSON-RPC response.

Source

pub async fn handle_async(&mut self, request: Value) -> Value

Handle either a persisted-session request or an asynchronous live runtime request.

Source

pub fn poll(&mut self) -> Vec<Value>

Poll all active subscriptions once and return zero or more JSON-RPC notifications. Recoverable follower errors are delivered as events.

Source

pub async fn poll_session_runtime_states(&mut self) -> Vec<Value>

Report each followed session’s live-runtime lifecycle state on that session’s own subscription, emitting only when the state changes.

A growing transcript is not evidence that an agent is working, so the state comes from the live-runtime registry and nowhere else. A followed session with no registered Supercode runtime — a harness running outside Supercode — reports persisted, which says plainly that its activity is unknown rather than guessing at it. These events carry no sequence number and no transcript content; they never interleave with the content follower’s sequenced stream.

Source

pub async fn poll_session_activities(&mut self) -> Vec<Value>

Poll normalized activity subscriptions, emitting only proven state transitions. Every subscription is bulk-sampled so stock-harness process and registry discovery happens once per UI, not once per row.

Source

pub fn poll_session_indexes(&mut self) -> Vec<Value>

Drain native-store invalidations and emit revisioned descriptor deltas. An idle subscription performs no catalog or transcript reads between its minute-scale recovery reconciliations.

Source

pub async fn poll_runtimes(&mut self) -> Vec<Value>

Non-blockingly sample one event from every connected live runtime.

Source

pub fn runtime_open(request: &Value) -> Option<RuntimeOpen>

Recognize the one request family whose waiting happens entirely outside this service’s state, and hand a transport the half it can run off the task that owns the service.

Opening a runtime is the only door here that waits on a foreign program: it spawns the harness’s own binary and completes that program’s protocol handshake, which takes as long as the program takes to answer. A transport that awaited the whole request inline would stop reading its own input for that whole time, so ONE slow launch would queue every later request on the same server — including reads like sessions.discover that touch no runtime at all. Splitting the request lets the transport spawn RuntimeOpen::open and keep reading, then pay only the short bookkeeping half (Self::register_open_runtime) when the runtime is up.

None for every other method: those are answered by Self::handle_async as before.

Source

pub fn detach(&self, request: &Value) -> Option<DetachedCall>

Recognize a DETACHED_METHODS request and hand a transport the whole of it: the service-state half is read here and now, and what remains waits on a foreign program with nothing of this service’s in hand.

Same reason as Self::runtime_open, different doors. Probing a harness starts it and completes its handshake; couriering a message runs a claude process to completion; a conversation verb runs the harness’s own CLI or calls its HTTP API. A transport that awaited any of those inline would stop reading its own input for that whole time, so one probe of an unhealthy harness would queue every later request on the same server.

Unlike an opening runtime there is no bookkeeping half: the answer DetachedCall::run produces is the caller’s complete response, so a transport writes it without coming back here.

None for every other method — including the LIVE sessions.new / sessions.reset door and runtimes.close, which wait on a runtime connection this service owns and so are split off by Self::detach_runtime instead.

Source

pub fn detach_runtime(&mut self, request: &Value) -> Option<DetachedCall>

Recognize the two doors that wait on a runtime THIS SERVICE OWNS, and hand a transport the whole of each by lending the connection out.

runtimes.close surrenders its runtime for good; the LIVE sessions.new / sessions.reset door borrows one for the length of the slash command and gives it back through Self::finish_detached. Both are bounded by RUNTIME_CONTROL_DEADLINE, and a wedged runtime spends all of it — which is exactly as long as a transport that awaited them inline would stop reading its own input.

None for every other method, and for the sessions.new / sessions.reset doors that are not live: Self::detach owns those.

Source

pub fn finish_detached(&mut self, answer: DetachedAnswer) -> Value

Take back whatever a detached call borrowed and hand over the caller’s response. Every answer from DetachedCall::run comes through here, so a lent-out connection is back in the service before the response that used it is written.

Source

pub async fn finish_runtime_open(&mut self, opened: OpenedRuntime) -> Value

Answer a request split out by Self::runtime_open and already awaited by RuntimeOpen::open: register the runtime this service now owns and build its JSON-RPC response.

Source

pub fn kill_all_runtime_groups(&self) -> usize

SIGKILL the process group of every runtime this service owns, without waiting on any of them.

A host leaving for good calls this BEFORE dropping the service. The handle this service holds is not the runtime’s connection: a hosted runtime’s real transport lives in the task driving it, so neither exiting the process nor dropping these handles reaches the harness process — while dropping them does remove each runtime’s live-runtime receipt. Signalling first is what keeps a removed receipt from advertising a harness that is still running.

Trait Implementations§

Source§

impl Default for HarnessSessionService

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl SdkService for HarnessSessionService

Source§

fn capabilities(&self) -> SdkCapabilities

Describe the versioned contract without invoking a runtime.
Source§

fn execute<'life0, 'async_trait>( &'life0 mut self, request: SdkRequest, ) -> Pin<Box<dyn Future<Output = Result<Value, SdkError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Execute one typed request. Transport correlation fields are not part of this API and therefore cannot contaminate canonical state.
Source§

fn events<'life0, 'async_trait>( &'life0 mut self, ) -> Pin<Box<dyn Future<Output = Result<Vec<SdkRuntimeEvent>, SdkError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Poll canonical runtime events without a transport envelope.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more