From eb4893a4bb3548b1f17bef89a10f24f0e3e5cadb Mon Sep 17 00:00:00 2001 From: shanu Date: Fri, 27 Mar 2026 14:38:47 +0530 Subject: [PATCH 1/4] feat(sdk-rust): add end-to-end example for TinyHumansMemoryClient - Introduced a new example script `example_e2e.rs` demonstrating the usage of the TinyHumansMemoryClient. - Implemented various steps including memory insertion, job checking, document listing, and querying memory. - Enhanced logging for better traceability during the execution of the example. - Updated `list_documents` method to accept parameters for namespace, limit, and offset, improving flexibility in document retrieval. --- packages/sdk-rust/examples/example_e2e.rs | 204 ++++++++++++++++++++++ packages/sdk-rust/src/lib.rs | 22 ++- packages/sdk-rust/src/types.rs | 11 ++ 3 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 packages/sdk-rust/examples/example_e2e.rs diff --git a/packages/sdk-rust/examples/example_e2e.rs b/packages/sdk-rust/examples/example_e2e.rs new file mode 100644 index 0000000..cf22fb2 --- /dev/null +++ b/packages/sdk-rust/examples/example_e2e.rs @@ -0,0 +1,204 @@ +use std::time::{SystemTime, UNIX_EPOCH}; +use tinyhumansai::{ + InsertMemoryParams, ListDocumentsParams, QueryMemoryParams, RecallMemoryParams, + TinyHumanConfig, TinyHumansError, TinyHumansMemoryClient, +}; + +const TINYHUMANS_BASE_URL: &str = "https://staging-api.alphahuman.xyz"; +const TINYHUMANS_TOKEN: &str = ""; // Add you api key here + +fn log_step(title: &str) { + println!("\n{}", "=".repeat(72)); + println!("[run] {title}"); + println!("{}", "=".repeat(72)); +} + +fn log_ok(title: &str) { + println!("[ok] {title}\n"); +} + +fn require_token() -> Result { + Ok(TINYHUMANS_TOKEN.to_string()) +} + +async fn step1_insert_memory( + client: &TinyHumansMemoryClient, + namespace: &str, + document_id: &str, +) -> Result { + log_step("step1: insertMemory"); + let insert_memory_res = client + .insert_memory(InsertMemoryParams { + title: "Sprint Dataset - Team Velocity".to_string(), + content: "Sprint snapshot: Team Atlas completed 42 story points with 3 blockers, \ +Team Beacon completed 35 story points with 1 blocker, Team Comet completed 48 story points \ +with 5 blockers, and Team Delta completed 39 story points with 2 blockers. The highest \ +velocity team is Team Comet and the fewest blockers team is Team Beacon." + .to_string(), + namespace: namespace.to_string(), + metadata: Some(serde_json::json!({ "source": "example_e2e.rs" })), + document_id: document_id.to_string(), + ..Default::default() + }) + .await?; + + log_ok("insertMemory"); + println!("insertMemoryRes {insert_memory_res:#?}"); + + match insert_memory_res.data.job_id { + Some(job_id) => Ok(job_id), + None => Err(TinyHumansError::Api { + message: "insertMemory response did not include jobId".to_string(), + status: 500, + body: None, + }), + } +} + +async fn step2_check_ingestion_job( + client: &TinyHumansMemoryClient, + insert_job_id: &str, +) -> Result<(), TinyHumansError> { + log_step("step2: getIngestionJob"); + let get_ingestion_job_res = client.get_ingestion_job(insert_job_id).await?; + log_ok("getIngestionJob"); + println!("getIngestionJobRes {get_ingestion_job_res:#?}"); + + let state = get_ingestion_job_res + .data + .state + .unwrap_or_default() + .to_lowercase(); + if state == "completed" || state == "done" || state == "success" || state == "succeeded" { + println!("[skip] waitForIngestionJob: job is already completed"); + return Ok(()); + } + + log_step("step2b: waitForIngestionJob"); + let wait_for_ingestion_job_res = client + .wait_for_ingestion_job(insert_job_id, Some(30_000), Some(1_000)) + .await?; + log_ok("waitForIngestionJob"); + println!("waitForIngestionJobRes {wait_for_ingestion_job_res:#?}"); + Ok(()) +} + +async fn step3_list_documents( + client: &TinyHumansMemoryClient, + namespace: &str, +) -> Result<(), TinyHumansError> { + log_step("step3: listDocuments"); + let list_documents_res = client + .list_documents(ListDocumentsParams { + namespace: Some(namespace.to_string()), + limit: Some(10.0), + offset: Some(0.0), + }) + .await?; + log_ok("listDocuments"); + println!("listDocumentsRes {list_documents_res:#?}"); + Ok(()) +} + +async fn step4_get_document( + client: &TinyHumansMemoryClient, + namespace: &str, + document_id: &str, +) -> Result<(), TinyHumansError> { + log_step("step4: getDocument"); + let get_document_res = client.get_document(document_id, Some(namespace)).await?; + log_ok("getDocument"); + println!("getDocumentRes {get_document_res:#?}"); + Ok(()) +} + +// This route may require additional permissions depending on environment. +async fn step5_query_memory( + client: &TinyHumansMemoryClient, + namespace: &str, +) -> Result<(), TinyHumansError> { + log_step("step5: queryMemory"); + let query_memory_res = client + .query_memory(QueryMemoryParams { + query: "Which team has the highest velocity and which team has the fewest blockers?" + .to_string(), + namespace: Some(namespace.to_string()), + include_references: Some(true), + max_chunks: Some(5.0), + ..Default::default() + }) + .await?; + log_ok("queryMemory"); + println!("queryMemoryRes {query_memory_res:#?}"); + Ok(()) +} + +async fn step6_recall_memory_context( + client: &TinyHumansMemoryClient, + namespace: &str, +) -> Result<(), TinyHumansError> { + log_step("step6: recallMemoryContext"); + let recall_memory_context_res = client + .recall_memory(RecallMemoryParams { + namespace: Some(namespace.to_string()), + max_chunks: Some(5.0), + }) + .await?; + log_ok("recallMemoryContext"); + println!("recallMemoryContextRes {recall_memory_context_res:#?}"); + Ok(()) +} + +#[tokio::main] +async fn main() { + let token = match require_token() { + Ok(token) => token, + Err(err) => { + eprintln!("E2E Rust SDK example failed."); + eprintln!("{err}"); + std::process::exit(1); + } + }; + + let mut config = TinyHumanConfig::new(token); + + config = config.with_base_url(TINYHUMANS_BASE_URL.to_string()); + + let client = match TinyHumansMemoryClient::new(config) { + Ok(client) => client, + Err(err) => { + eprintln!("E2E Rust SDK example failed."); + eprintln!("{err}"); + std::process::exit(1); + } + }; + + let ts = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_millis()) + .unwrap_or(0); + let namespace = "sdk-rust-e2e".to_string(); + let single_doc_id = format!("sdk-rust-e2e-doc-single-{ts}"); + + let result = async { + // let insert_job_id = step1_insert_memory(&client, &namespace, &single_doc_id).await?; + // step2_check_ingestion_job(&client, &insert_job_id).await?; + step3_list_documents(&client, &namespace).await?; + // step4_get_document(&client, &namespace, &single_doc_id).await?; + + if let Err(err) = step5_query_memory(&client, &namespace).await { + eprintln!("[warn] step5 queryMemory skipped: {err}"); + } + step6_recall_memory_context(&client, &namespace).await?; + + println!("\nE2E Rust SDK example completed."); + Ok::<(), TinyHumansError>(()) + } + .await; + + if let Err(err) = result { + eprintln!("\nE2E Rust SDK example failed."); + eprintln!("{err}"); + std::process::exit(1); + } +} \ No newline at end of file diff --git a/packages/sdk-rust/src/lib.rs b/packages/sdk-rust/src/lib.rs index 7ca0597..331c6c9 100644 --- a/packages/sdk-rust/src/lib.rs +++ b/packages/sdk-rust/src/lib.rs @@ -315,8 +315,26 @@ impl TinyHumansMemoryClient { } /// List ingested memory documents. GET /memory/documents - pub async fn list_documents(&self) -> Result { - self.get("/memory/documents").await + pub async fn list_documents( + &self, + params: ListDocumentsParams, + ) -> Result { + let mut qs_parts: Vec = Vec::new(); + if let Some(ns) = params.namespace { + qs_parts.push(format!("namespace={ns}")); + } + if let Some(limit) = params.limit { + qs_parts.push(format!("limit={limit}")); + } + if let Some(offset) = params.offset { + qs_parts.push(format!("offset={offset}")); + } + let qs = if qs_parts.is_empty() { + String::new() + } else { + format!("?{}", qs_parts.join("&")) + }; + self.get(&format!("/memory/documents{qs}")).await } /// Get details for a memory document. GET /memory/documents/{documentId} diff --git a/packages/sdk-rust/src/types.rs b/packages/sdk-rust/src/types.rs index 499473e..e218e1d 100644 --- a/packages/sdk-rust/src/types.rs +++ b/packages/sdk-rust/src/types.rs @@ -419,6 +419,17 @@ pub struct BatchInsertDocumentsParams { pub items: Vec, } +#[derive(Debug, Clone, Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ListDocumentsParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub namespace: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub offset: Option, +} + // Document route response schemas are not specified in swagger. pub type InsertDocumentResponse = serde_json::Value; pub type BatchInsertDocumentsResponse = serde_json::Value; From eb6314c1363462547e4e9a7580e2d403e6f915f8 Mon Sep 17 00:00:00 2001 From: shanu Date: Fri, 27 Mar 2026 14:40:42 +0530 Subject: [PATCH 2/4] fix(sdk-rust): clean up whitespace and ensure newline at end of file - Removed unnecessary whitespace in `example_e2e.rs` for cleaner code. - Added a newline at the end of `example_e2e.rs` to adhere to file formatting standards. - Reformatted error message in `lib.rs` for better readability in validation checks. --- packages/sdk-rust/examples/example_e2e.rs | 4 ++-- packages/sdk-rust/src/lib.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/sdk-rust/examples/example_e2e.rs b/packages/sdk-rust/examples/example_e2e.rs index cf22fb2..d181222 100644 --- a/packages/sdk-rust/examples/example_e2e.rs +++ b/packages/sdk-rust/examples/example_e2e.rs @@ -161,7 +161,7 @@ async fn main() { }; let mut config = TinyHumanConfig::new(token); - + config = config.with_base_url(TINYHUMANS_BASE_URL.to_string()); let client = match TinyHumansMemoryClient::new(config) { @@ -201,4 +201,4 @@ async fn main() { eprintln!("{err}"); std::process::exit(1); } -} \ No newline at end of file +} diff --git a/packages/sdk-rust/src/lib.rs b/packages/sdk-rust/src/lib.rs index 331c6c9..c3d1e71 100644 --- a/packages/sdk-rust/src/lib.rs +++ b/packages/sdk-rust/src/lib.rs @@ -306,9 +306,10 @@ impl TinyHumansMemoryClient { } for (i, item) in params.items.iter().enumerate() { if item.document_id.is_empty() { - return Err(TinyHumansError::Validation( - format!("items[{}]: documentId is required", i), - )); + return Err(TinyHumansError::Validation(format!( + "items[{}]: documentId is required", + i + ))); } } self.post("/memory/documents/batch", ¶ms).await @@ -476,10 +477,9 @@ impl TinyHumansMemoryClient { ["completed", "done", "succeeded", "success"] .into_iter() .collect(); - let failed: std::collections::HashSet<&str> = - ["failed", "error", "cancelled", "canceled"] - .into_iter() - .collect(); + let failed: std::collections::HashSet<&str> = ["failed", "error", "cancelled", "canceled"] + .into_iter() + .collect(); let deadline = std::time::Instant::now() + std::time::Duration::from_millis(timeout); let mut last: Option = None; From 36a765e50cd1d56d4065f236a4a2d72915933a7f Mon Sep 17 00:00:00 2001 From: shanu Date: Fri, 27 Mar 2026 14:54:27 +0530 Subject: [PATCH 3/4] fix(sdk-rust): update example scripts for improved functionality - Updated `example_e2e.rs` to correctly utilize the document ID in memory operations, ensuring all steps are executed. - Enhanced `test_routes.rs` to include parameters for the `list_documents` method, allowing for better control over document retrieval. --- packages/sdk-rust/examples/example_e2e.rs | 8 ++++---- packages/sdk-rust/examples/test_routes.rs | 16 +++++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/sdk-rust/examples/example_e2e.rs b/packages/sdk-rust/examples/example_e2e.rs index d181222..5294a09 100644 --- a/packages/sdk-rust/examples/example_e2e.rs +++ b/packages/sdk-rust/examples/example_e2e.rs @@ -178,13 +178,13 @@ async fn main() { .map(|d| d.as_millis()) .unwrap_or(0); let namespace = "sdk-rust-e2e".to_string(); - let single_doc_id = format!("sdk-rust-e2e-doc-single-{ts}"); + let _single_doc_id = format!("sdk-rust-e2e-doc-single-{ts}"); let result = async { - // let insert_job_id = step1_insert_memory(&client, &namespace, &single_doc_id).await?; - // step2_check_ingestion_job(&client, &insert_job_id).await?; + let insert_job_id = step1_insert_memory(&client, &namespace, &single_doc_id).await?; + step2_check_ingestion_job(&client, &insert_job_id).await?; step3_list_documents(&client, &namespace).await?; - // step4_get_document(&client, &namespace, &single_doc_id).await?; + step4_get_document(&client, &namespace, &single_doc_id).await?; if let Err(err) = step5_query_memory(&client, &namespace).await { eprintln!("[warn] step5 queryMemory skipped: {err}"); diff --git a/packages/sdk-rust/examples/test_routes.rs b/packages/sdk-rust/examples/test_routes.rs index 050fcd0..1d68654 100644 --- a/packages/sdk-rust/examples/test_routes.rs +++ b/packages/sdk-rust/examples/test_routes.rs @@ -4,10 +4,10 @@ use std::time::{SystemTime, UNIX_EPOCH}; use tinyhumansai::{ BatchDocumentItem, BatchInsertDocumentsParams, ChatMessage, DeleteMemoryParams, - InsertDocumentParams, InsertMemoryParams, InteractionLevel, MemoryChatParams, - MemoryConversationParams, MemoryInteractionsParams, MemoryThoughtsParams, QueryMemoriesParams, - QueryMemoryParams, RecallMemoriesContextParams, RecallMemoriesParams, RecallMemoryParams, - SourceType, TinyHumanConfig, TinyHumansError, TinyHumansMemoryClient, + InsertDocumentParams, InsertMemoryParams, InteractionLevel, ListDocumentsParams, + MemoryChatParams, MemoryConversationParams, MemoryInteractionsParams, MemoryThoughtsParams, + QueryMemoriesParams, QueryMemoryParams, RecallMemoriesContextParams, RecallMemoriesParams, + RecallMemoryParams, SourceType, TinyHumanConfig, TinyHumansError, TinyHumansMemoryClient, }; type CheckResults = Vec<(String, bool, String)>; @@ -294,7 +294,13 @@ async fn main() { push_result( &mut results, "list_documents", - client.list_documents().await, + client + .list_documents(ListDocumentsParams { + namespace: Some(namespace.clone()), + limit: Some(50.0), + offset: Some(0.0), + }) + .await, false, ); From 6fc8b3cb4ef067c45aecdf2e5ae02a0a3b372486 Mon Sep 17 00:00:00 2001 From: shanu Date: Fri, 27 Mar 2026 15:13:24 +0530 Subject: [PATCH 4/4] fix(sdk-rust): correct variable naming in example_e2e.rs - Updated the variable name from `_single_doc_id` to `single_doc_id` for clarity and consistency in the example script. --- packages/sdk-rust/examples/example_e2e.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sdk-rust/examples/example_e2e.rs b/packages/sdk-rust/examples/example_e2e.rs index 5294a09..2086af1 100644 --- a/packages/sdk-rust/examples/example_e2e.rs +++ b/packages/sdk-rust/examples/example_e2e.rs @@ -178,7 +178,7 @@ async fn main() { .map(|d| d.as_millis()) .unwrap_or(0); let namespace = "sdk-rust-e2e".to_string(); - let _single_doc_id = format!("sdk-rust-e2e-doc-single-{ts}"); + let single_doc_id = format!("sdk-rust-e2e-doc-single-{ts}"); let result = async { let insert_job_id = step1_insert_memory(&client, &namespace, &single_doc_id).await?;