huskies: merge 608_story_extract_io_and_anthropic_services

This commit is contained in:
dave
2026-04-24 15:50:26 +00:00
parent aba3120388
commit 65c896f07f
8 changed files with 617 additions and 291 deletions
-168
View File
@@ -31,35 +31,6 @@ pub struct ChatResult {
pub session_id: Option<String>,
}
fn get_anthropic_api_key_exists_impl(store: &dyn StoreOps) -> bool {
match store.get(KEY_ANTHROPIC_API_KEY) {
Some(value) => value.as_str().map(|k| !k.is_empty()).unwrap_or(false),
None => false,
}
}
fn set_anthropic_api_key_impl(store: &dyn StoreOps, api_key: &str) -> Result<(), String> {
store.set(KEY_ANTHROPIC_API_KEY, json!(api_key));
store.save()?;
match store.get(KEY_ANTHROPIC_API_KEY) {
Some(value) => {
if let Some(retrieved) = value.as_str() {
if retrieved != api_key {
return Err("Retrieved key does not match saved key".to_string());
}
} else {
return Err("Stored value is not a string".to_string());
}
}
None => {
return Err("API key was saved but cannot be retrieved".to_string());
}
}
Ok(())
}
fn get_anthropic_api_key_impl(store: &dyn StoreOps) -> Result<String, String> {
match store.get(KEY_ANTHROPIC_API_KEY) {
Some(value) => {
@@ -172,14 +143,6 @@ pub async fn get_ollama_models(base_url: Option<String>) -> Result<Vec<String>,
OllamaProvider::get_models(&url).await
}
pub fn get_anthropic_api_key_exists(store: &dyn StoreOps) -> Result<bool, String> {
Ok(get_anthropic_api_key_exists_impl(store))
}
pub fn set_anthropic_api_key(store: &dyn StoreOps, api_key: String) -> Result<(), String> {
set_anthropic_api_key_impl(store, &api_key)
}
/// Build a prompt for Claude Code that includes prior conversation history.
///
/// When a Claude Code session cannot be resumed (no session_id), we embed
@@ -627,22 +590,6 @@ mod tests {
save_should_fail: false,
}
}
fn with_save_error() -> Self {
Self {
data: Mutex::new(HashMap::new()),
save_should_fail: true,
}
}
fn with_entry(key: &str, value: serde_json::Value) -> Self {
let mut map = HashMap::new();
map.insert(key.to_string(), value);
Self {
data: Mutex::new(map),
save_should_fail: false,
}
}
}
impl StoreOps for MockStore {
@@ -695,121 +642,6 @@ mod tests {
assert!(result.is_ok());
}
// ---------------------------------------------------------------------------
// get_anthropic_api_key_exists_impl
// ---------------------------------------------------------------------------
#[test]
fn api_key_exists_when_key_is_present_and_non_empty() {
let store = MockStore::with_entry("anthropic_api_key", json!("sk-test-key"));
assert!(get_anthropic_api_key_exists_impl(&store));
}
#[test]
fn api_key_exists_returns_false_when_key_is_empty_string() {
let store = MockStore::with_entry("anthropic_api_key", json!(""));
assert!(!get_anthropic_api_key_exists_impl(&store));
}
#[test]
fn api_key_exists_returns_false_when_key_absent() {
let store = MockStore::new();
assert!(!get_anthropic_api_key_exists_impl(&store));
}
#[test]
fn api_key_exists_returns_false_when_value_is_not_string() {
let store = MockStore::with_entry("anthropic_api_key", json!(42));
assert!(!get_anthropic_api_key_exists_impl(&store));
}
// ---------------------------------------------------------------------------
// get_anthropic_api_key_impl
// ---------------------------------------------------------------------------
#[test]
fn get_api_key_returns_key_when_present() {
let store = MockStore::with_entry("anthropic_api_key", json!("sk-test-key"));
let result = get_anthropic_api_key_impl(&store);
assert_eq!(result.unwrap(), "sk-test-key");
}
#[test]
fn get_api_key_errors_when_empty() {
let store = MockStore::with_entry("anthropic_api_key", json!(""));
let result = get_anthropic_api_key_impl(&store);
assert!(result.is_err());
assert!(result.unwrap_err().contains("empty"));
}
#[test]
fn get_api_key_errors_when_absent() {
let store = MockStore::new();
let result = get_anthropic_api_key_impl(&store);
assert!(result.is_err());
assert!(result.unwrap_err().contains("not found"));
}
#[test]
fn get_api_key_errors_when_value_not_string() {
let store = MockStore::with_entry("anthropic_api_key", json!(123));
let result = get_anthropic_api_key_impl(&store);
assert!(result.is_err());
assert!(result.unwrap_err().contains("not a string"));
}
// ---------------------------------------------------------------------------
// set_anthropic_api_key_impl
// ---------------------------------------------------------------------------
#[test]
fn set_api_key_stores_and_returns_ok() {
let store = MockStore::new();
let result = set_anthropic_api_key_impl(&store, "sk-my-key");
assert!(result.is_ok());
assert_eq!(store.get("anthropic_api_key"), Some(json!("sk-my-key")));
}
#[test]
fn set_api_key_returns_error_when_save_fails() {
let store = MockStore::with_save_error();
let result = set_anthropic_api_key_impl(&store, "sk-my-key");
assert!(result.is_err());
assert!(result.unwrap_err().contains("mock save error"));
}
// ---------------------------------------------------------------------------
// Public wrappers: get_anthropic_api_key_exists / set_anthropic_api_key
// ---------------------------------------------------------------------------
#[test]
fn public_api_key_exists_returns_ok_bool() {
let store = MockStore::with_entry("anthropic_api_key", json!("sk-abc"));
let result = get_anthropic_api_key_exists(&store);
assert_eq!(result, Ok(true));
}
#[test]
fn public_api_key_exists_false_when_absent() {
let store = MockStore::new();
let result = get_anthropic_api_key_exists(&store);
assert_eq!(result, Ok(false));
}
#[test]
fn public_set_api_key_succeeds() {
let store = MockStore::new();
let result = set_anthropic_api_key(&store, "sk-xyz".to_string());
assert!(result.is_ok());
}
#[test]
fn public_set_api_key_propagates_save_error() {
let store = MockStore::with_save_error();
let result = set_anthropic_api_key(&store, "sk-xyz".to_string());
assert!(result.is_err());
}
// ---------------------------------------------------------------------------
// get_tool_definitions
// ---------------------------------------------------------------------------