use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use async_trait::async_trait;
use serde_json::json;
use supercode_harness::{
load_session_path, Agent, ChatMessage, ChatRequest, Config, FrontendElicitationAction,
FrontendResponse, FrontendRuntimeError, HarnessSessionService, Provider, RpcEngine,
RuntimeSubmitError, SdkOperation, SdkRequest, SdkRuntime, SdkService, Session, SessionSource,
Usage,
};
fn fixture() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/pi_session.jsonl")
}
fn locator() -> serde_json::Value {
json!({
"harness":"pi",
"session_id":"1e6f2a3b-0000-4000-8000-000000000001",
"storage":{"kind":"file", "path":fixture()},
})
}
#[test]
fn sdk_path_load_prefers_the_full_native_store_sidecar() {
let nonce = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let root = std::env::temp_dir().join(format!(
"supercode-sdk-native-family-{}-{nonce}",
std::process::id()
));
std::fs::create_dir_all(&root).unwrap();
let name = "continued-claude-session";
let transcript = root.join(format!("{name}.jsonl"));
let sidecar = root.join(format!("{name}.sidecar.jsonl"));
let metadata = root.join(format!("{name}.meta.json"));
let source = concat!(
"{\"type\":\"user\",\"sessionId\":\"source-id\",",
"\"message\":{\"role\":\"user\",\"content\":\"imported fact\"}}\n"
);
let imported = Session::from_claude_code_str(source).unwrap();
let appended = [
ChatMessage::user("continued prompt"),
ChatMessage::assistant("continued answer"),
];
std::fs::write(&sidecar, imported.to_native_jsonl_v2(&appended)).unwrap();
std::fs::write(
&transcript,
serde_json::to_string(&ChatMessage::user("reduced working view")).unwrap(),
)
.unwrap();
std::fs::write(metadata, "{}").unwrap();
let loaded = load_session_path(&transcript, None).unwrap();
assert_eq!(loaded.meta.source, SessionSource::ClaudeCode);
assert_eq!(loaded.meta.session_id.as_deref(), Some(name));
assert_eq!(loaded.raw[0], source.trim_end());
assert_eq!(
loaded
.messages
.iter()
.filter_map(|message| message.content.as_deref())
.collect::<Vec<_>>(),
["imported fact", "continued prompt", "continued answer"]
);
assert!(loaded
.messages
.iter()
.all(|message| message.content.as_deref() != Some("reduced working view")));
std::fs::remove_dir_all(root).ok();
}
struct BlockingProvider {
entered: tokio::sync::Notify,
release: tokio::sync::Notify,
}
struct SharedProvider(Arc<BlockingProvider>);
#[async_trait]
impl Provider for SharedProvider {
async fn complete(
&self,
_request: &ChatRequest,
on_delta: &(dyn for<'a> Fn(&'a str) + Send + Sync),
) -> supercode_harness::Result<(ChatMessage, Usage)> {
self.0.entered.notify_one();
self.0.release.notified().await;
on_delta("adapter-free reply");
Ok((
ChatMessage::assistant("adapter-free reply"),
Usage::default(),
))
}
}
#[tokio::test]
async fn canonical_sdk_semantics_survive_removing_every_surface_adapter() {
let mut service = HarnessSessionService::new();
let loaded = service
.execute(SdkRequest {
operation: SdkOperation::Load,
params: json!({"locator":locator()}),
})
.await
.unwrap();
assert_eq!(loaded["session"]["session_id"], locator()["session_id"]);
let exported = service
.execute(SdkRequest {
operation: SdkOperation::Export,
params: json!({"locator":locator(), "target_harness":"pi"}),
})
.await
.unwrap();
assert_eq!(exported["artifact"]["session_id"], locator()["session_id"]);
let provider = Arc::new(BlockingProvider {
entered: tokio::sync::Notify::new(),
release: tokio::sync::Notify::new(),
});
let persisted = Arc::new(Mutex::new(String::new()));
let persisted_hook = persisted.clone();
let agent = Agent::with_provider(
Config::builder().system_prompt("SDK-only proof").build(),
Box::new(SharedProvider(provider.clone())),
);
let runtime = RpcEngine::new_named(
agent,
"adapter-free-stable-id",
Some(Box::new(move |agent: &supercode_harness::SdkAgent| {
*persisted_hook.lock().unwrap() = serde_json::to_string(agent.history()).unwrap();
})),
);
let mut events = runtime.attach(50).await.unwrap();
let active = {
let runtime = runtime.clone();
tokio::spawn(async move { SdkRuntime::submit(runtime.as_ref(), "one prompt".into()).await })
};
provider.entered.notified().await;
assert_eq!(
SdkRuntime::submit(runtime.as_ref(), "busy prompt".into())
.await
.unwrap_err(),
FrontendRuntimeError::Submit(RuntimeSubmitError::Busy)
);
assert_eq!(
SdkRuntime::respond(
runtime.as_ref(),
FrontendResponse::Other {
request_id: 99,
action: FrontendElicitationAction::Cancel,
content: None,
},
)
.await
.unwrap_err(),
FrontendRuntimeError::UnsupportedAction("respond")
);
provider.release.notify_waiters();
assert_eq!(active.await.unwrap().unwrap(), "adapter-free reply");
let mut sequence = Vec::new();
loop {
let event = events.next_event().await.unwrap();
let terminal = event.kind == "turn_succeeded";
sequence.push((event.sequence, event.kind));
if terminal {
break;
}
}
assert_eq!(events.descriptor.session_id, "adapter-free-stable-id");
assert!(sequence.windows(2).all(|pair| pair[0].0 < pair[1].0));
assert!(persisted.lock().unwrap().contains("adapter-free reply"));
runtime.shutdown().await;
}