52 lines
1.9 KiB
Rust
52 lines
1.9 KiB
Rust
//! Task-local session identifier for the requesting MCP client.
|
|||
|
|
//!
|
||
|
|
//! Threaded ambiently through tool dispatch (same pattern as
|
||
|
|
//! [`super::progress::EMITTER`]) so a deeply-nested handler — currently only
|
||
|
|
//! `tool_prompt_permission` — can scope decisions per requesting agent
|
||
|
|
//! without adding a parameter to `dispatch_tool_call` and every one of its
|
||
|
|
//! ~40 match arms.
|
||
|
|
//!
|
||
|
|
//! The HTTP MCP handler installs the scope before dispatching a `tools/call`
|
||
|
|
//! request, populated from the `X-Huskies-Session` header that per-story
|
||
|
|
//! worktrees embed in their `.mcp.json` (see `worktree::write_mcp_json`).
|
||
|
|
//! Callers with no header (the main interactive chat CLI, API-based runtimes
|
||
|
|
//! that invoke `dispatch_tool_call` directly) fall back to a fixed
|
||
|
|
//! `"default"` key — there is only ever one such session per server process,
|
||
|
|
//! so no cross-story leakage results from sharing that bucket.
|
||
|
|
|
||
|
|
/// Session key used when no `X-Huskies-Session` header was present.
|
||
|
|
pub const DEFAULT_SESSION: &str = "default";
|
||
|
|
|
||
|
|
tokio::task_local! {
|
||
|
|
/// Set by the MCP HTTP handler before dispatching a `tools/call` request.
|
||
|
|
/// Unset in tests and in non-HTTP dispatch paths, where [`current`] falls
|
||
|
|
/// back to [`DEFAULT_SESSION`].
|
||
|
|
pub static SESSION_ID: String;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Return the current request's session id, or [`DEFAULT_SESSION`] if no
|
||
|
|
/// scope is installed.
|
||
|
|
pub fn current() -> String {
|
||
|
|
SESSION_ID
|
||
|
|
.try_with(Clone::clone)
|
||
|
|
.unwrap_or_else(|_| DEFAULT_SESSION.to_string())
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod tests {
|
||
|
|
use super::*;
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn current_falls_back_to_default_without_scope() {
|
||
|
|
assert_eq!(current(), DEFAULT_SESSION);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn current_reads_installed_scope() {
|
||
|
|
let value = SESSION_ID
|
||
|
|
.scope("1218".to_string(), async { current() })
|
||
|
|
.await;
|
||
|
|
assert_eq!(value, "1218");
|
||
|
|
}
|
||
|
|
}
|