supercode-interchange 0.4.14

Canonical, provider-neutral session interchange primitives for Supercode
Documentation
//! OpenClaw session codec: loader, key parsing and header nouns.

use super::*;

pub use crate::ontology::parse_openclaw_session_key;
use crate::ontology::Binding;

/// OpenClaw sessions live under `agents/<agentId>/…`; the agent id is the profile.
pub fn openclaw_agent_id_from_path(path: &std::path::Path) -> Option<String> {
    let comps: Vec<String> = path
        .components()
        .map(|c| c.as_os_str().to_string_lossy().into_owned())
        .collect();
    comps
        .windows(2)
        .find(|w| w[0] == "agents")
        .map(|w| w[1].clone())
}

impl Session {
    /// Load an OpenClaw agent session (`~/.openclaw/agents/<id>/sessions/
    /// <uuid>.jsonl`, openclaw >= 2026.7): pi session-format v3 with the
    /// openclaw dialect divergences (READ-ONLY tier, UNI-16):
    ///
    /// - `type:"leaf"` navigation-control entries REDIRECT the active leaf to
    ///   their `targetId` — pi's own "last entry in file order" anchor rule is
    ///   wrong for them, so the LAST leaf entry wins (a dangling or null
    ///   `targetId` fails safe to the default rule).
    /// - `appendMode:"side"` entries never become the anchor.
    /// - Vendor-namespaced `__openclaw` message metadata is stamped onto the
    ///   loaded message as `openclaw_<key>` metadata — provenance preserved,
    ///   never interpreted.
    ///
    /// A session file that references OTHER sessions (delegate/session-key
    /// markers) decodes STANDALONE: references survive as metadata/raw only
    /// and are never dereferenced — a nested-runtime transcript is a mirror,
    /// never a recursive load.
    pub fn from_openclaw_str(jsonl: &str) -> Result<Session> {
        Self::from_pi_v3_dialect(jsonl, SessionSource::OpenClaw, true)
    }
}

/// ORCH-3: an OpenClaw transcript header may carry the gateway session key
/// (`sessionKey` at the top level or under `__openclaw`); derive the nouns
/// from it. Absent key → nothing is claimed.
pub(crate) fn openclaw_capture_header_nouns(header: &Value, meta: &mut SessionMeta) {
    let key = header
        .get("sessionKey")
        .or_else(|| header.get("__openclaw").and_then(|o| o.get("sessionKey")))
        .and_then(Value::as_str);
    let Some(key) = key else { return };
    if let Some(binding) = Binding::from_openclaw_key(key, None, None, None) {
        if meta.profile.is_none() {
            meta.profile = binding.profile.clone();
        }
        meta.surface = Some(binding.key.clone());
        meta.trigger = Some(binding.trigger);
        meta.recurrence = binding.recurrence;
    }
}