diff --git a/docs/sdk-rust-e2e-test-run.md b/docs/sdk-rust-e2e-test-run.md index 1b70a7792..da23816b1 100644 --- a/docs/sdk-rust-e2e-test-run.md +++ b/docs/sdk-rust-e2e-test-run.md @@ -12,14 +12,14 @@ The file is a standalone end-to-end integration program (not a `#[test]`-annotated unit test). It exercises the `tinyhumansai` Rust SDK against the staging API in six sequential steps: -| Step | Operation | SDK method | -|------|-----------|------------| -| 1 | Insert a memory document | `insert_memory` | -| 2 | Poll ingestion job until complete | `get_ingestion_job` + `wait_for_ingestion_job` | -| 3 | List documents filtered by namespace | `list_documents` | -| 4 | Fetch the specific document | `get_document` | -| 5 | Semantic query over the namespace | `query_memory` | -| 6 | Recall all memory context | `recall_memory` | +| Step | Operation | SDK method | +| ---- | ------------------------------------ | ---------------------------------------------- | +| 1 | Insert a memory document | `insert_memory` | +| 2 | Poll ingestion job until complete | `get_ingestion_job` + `wait_for_ingestion_job` | +| 3 | List documents filtered by namespace | `list_documents` | +| 4 | Fetch the specific document | `get_document` | +| 5 | Semantic query over the namespace | `query_memory` | +| 6 | Recall all memory context | `recall_memory` | The document inserted contains sprint velocity data for four teams (Atlas, Beacon, Comet, Delta). @@ -98,30 +98,30 @@ Initial poll returned state `processing`, so the SDK waited. Job completed succe Key stats from the completed job response: -| Metric | Value | -|--------|-------| -| Chunks new | 1 | -| Chunks total | 1 | -| Chunks deduplicated | 0 | -| Entities extracted | 15 | -| Relations extracted | 25 | -| Sections | 1 | -| Source type | `doc` | -| Embedding tokens used | 244 | -| Cost (USD) | $0.00000488 | +| Metric | Value | +| --------------------- | ----------- | +| Chunks new | 1 | +| Chunks total | 1 | +| Chunks deduplicated | 0 | +| Entities extracted | 15 | +| Relations extracted | 25 | +| Sections | 1 | +| Source type | `doc` | +| Embedding tokens used | 244 | +| Cost (USD) | $0.00000488 | Timing breakdown (selected): -| Stage | Seconds | -|-------|---------| -| Chunking | 0.000826 | -| Chunk embedding | 0.2688 | -| Chunk storage | 0.2049 | -| Entity extraction | 0.8131 | -| Entity embedding | 0.0476 | -| Graph structure | 0.2427 | -| Relationship storage | 0.3800 | -| Storage total | 1.2504 | +| Stage | Seconds | +| -------------------- | -------- | +| Chunking | 0.000826 | +| Chunk embedding | 0.2688 | +| Chunk storage | 0.2049 | +| Entity extraction | 0.8131 | +| Entity embedding | 0.0476 | +| Graph structure | 0.2427 | +| Relationship storage | 0.3800 | +| Storage total | 1.2504 | --- @@ -133,11 +133,11 @@ This run uses the updated `list_documents(ListDocumentsParams { namespace, limit **4 documents returned** (all previous E2E runs in this namespace): -| Document ID | Created at | -|-------------|------------| -| `sdk-rust-e2e-doc-single-1774598994566` | 2026-03-27T08:09:56 | -| `sdk-rust-e2e-doc-single-1774600415507` | 2026-03-27T08:33:37 | -| `sdk-rust-e2e-doc-single-1774604625874` | 2026-03-27T09:43:47 | +| Document ID | Created at | +| --------------------------------------- | ------------------------------ | +| `sdk-rust-e2e-doc-single-1774598994566` | 2026-03-27T08:09:56 | +| `sdk-rust-e2e-doc-single-1774600415507` | 2026-03-27T08:33:37 | +| `sdk-rust-e2e-doc-single-1774604625874` | 2026-03-27T09:43:47 | | `sdk-rust-e2e-doc-single-1774605977640` | 2026-03-27T10:06:20 ← this run | All share `namespace: "sdk-rust-e2e"`, `title: "Sprint Dataset - Team Velocity"`, `chunk_count: 1`. @@ -200,15 +200,16 @@ The relevant chunk was retrieved correctly. The LLM context message assembled by Top entity mentions extracted from the chunk (by normalized importance): -| Entity | Normalized importance | Count | -|--------|-----------------------|-------| -| THE FEWEST BLOCKERS TEAM | 1.000 | 6 | -| 42 STORY POINTS | 0.842 | 14 | -| TEAM BEACON | 0.486 | 2 | -| TEAM COMET | 0.476 | 2 | -| THE HIGHEST VELOCITY TEAM | 0.440 | 4 | +| Entity | Normalized importance | Count | +| ------------------------- | --------------------- | ----- | +| THE FEWEST BLOCKERS TEAM | 1.000 | 6 | +| 42 STORY POINTS | 0.842 | 14 | +| TEAM BEACON | 0.486 | 2 | +| TEAM COMET | 0.476 | 2 | +| THE HIGHEST VELOCITY TEAM | 0.440 | 4 | **Usage:** + - Embedding tokens: 20 - Cost: $0.0000004 - Cached: false @@ -222,10 +223,7 @@ Top entity mentions extracted from the chunk (by normalized importance): **Request body** (serialized from `RecallMemoryParams` with `#[serde(rename_all = "camelCase")]`): ```json -{ - "namespace": "sdk-rust-e2e", - "maxChunks": 5.0 -} +{ "namespace": "sdk-rust-e2e", "maxChunks": 5.0 } ``` Recall (no query — returns all recent/relevant context) returned the same chunk with a higher score of `31.357` (recall scoring differs from query scoring). @@ -241,14 +239,14 @@ The LLM context message was identical to step 5. ## Changes since previous run -| Area | Previous run | This run | -|------|-------------|----------| -| `step3_list_documents` signature | `list_documents()` — no args | `list_documents(ListDocumentsParams { namespace, limit, offset })` | -| Step 3 result | Empty `documents: []` (no filter) | 4 documents returned (namespace filter working) | -| Job ID | `4b3cc8e2-...` | `a2a1396c-...` | -| Document ID | `sdk-rust-e2e-doc-single-1774600415507` | `sdk-rust-e2e-doc-single-1774605977640` | -| Ingestion latency | 1.7791 s | 2.6173 s | -| Entity extraction time | 0.0117 s | 0.8131 s | +| Area | Previous run | This run | +| -------------------------------- | --------------------------------------- | ------------------------------------------------------------------ | +| `step3_list_documents` signature | `list_documents()` — no args | `list_documents(ListDocumentsParams { namespace, limit, offset })` | +| Step 3 result | Empty `documents: []` (no filter) | 4 documents returned (namespace filter working) | +| Job ID | `4b3cc8e2-...` | `a2a1396c-...` | +| Document ID | `sdk-rust-e2e-doc-single-1774600415507` | `sdk-rust-e2e-doc-single-1774605977640` | +| Ingestion latency | 1.7791 s | 2.6173 s | +| Entity extraction time | 0.0117 s | 0.8131 s | --- @@ -259,6 +257,7 @@ E2E Rust SDK example completed. ``` All 6 steps passed. The SDK correctly: + - Inserted a document and received a job ID - Polled and waited for the ingestion job to reach `completed` - Listed documents filtered by namespace (returning all 4 prior E2E inserts) diff --git a/docs/tinyhumansai-sdk.md b/docs/tinyhumansai-sdk.md index 4412543f9..81c215628 100644 --- a/docs/tinyhumansai-sdk.md +++ b/docs/tinyhumansai-sdk.md @@ -21,6 +21,7 @@ let config = config.with_base_url("https://staging-api.alphahuman.xyz"); ``` Base URL resolution order: + 1. `with_base_url(...)` call 2. `TINYHUMANS_BASE_URL` env var 3. `NEOCORTEX_BASE_URL` env var @@ -60,17 +61,17 @@ let job_id = res.data.job_id; // Option **`InsertMemoryParams`** -| Field | Type | Required | Description | -|-------|------|----------|-------------| -| `title` | `String` | Yes | Document title | -| `content` | `String` | Yes | Document text content | -| `namespace` | `String` | Yes | Logical partition for the document | -| `document_id` | `String` | Yes | Caller-supplied unique ID | -| `source_type` | `Option` | No | `Doc` (default), `Chat`, or `Email` | -| `metadata` | `Option` | No | Arbitrary JSON metadata | -| `priority` | `Option` | No | `High`, `Medium`, or `Low` | -| `created_at` | `Option` | No | Unix timestamp (ms) | -| `updated_at` | `Option` | No | Unix timestamp (ms) | +| Field | Type | Required | Description | +| ------------- | --------------------------- | -------- | ----------------------------------- | +| `title` | `String` | Yes | Document title | +| `content` | `String` | Yes | Document text content | +| `namespace` | `String` | Yes | Logical partition for the document | +| `document_id` | `String` | Yes | Caller-supplied unique ID | +| `source_type` | `Option` | No | `Doc` (default), `Chat`, or `Email` | +| `metadata` | `Option` | No | Arbitrary JSON metadata | +| `priority` | `Option` | No | `High`, `Medium`, or `Low` | +| `created_at` | `Option` | No | Unix timestamp (ms) | +| `updated_at` | `Option` | No | Unix timestamp (ms) | **Serialised request body** (fields with `None` values are omitted): @@ -115,17 +116,17 @@ println!("{:?}", res.data.state); // Some("processing") | Some("completed") | .. **`IngestionJobStatusResponse`** -| Field | Type | Description | -|-------|------|-------------| -| `job_id` | `Option` | The job ID | -| `state` | `Option` | `pending`, `processing`, `completed`, `failed`, etc. | -| `endpoint` | `Option` | API endpoint that created the job | -| `attempts` | `Option` | Number of execution attempts | -| `error` | `Option` | Error message if failed | -| `response` | `Option` | Full ingestion result (stats, timings, usage) on completion | -| `created_at` | `Option` | ISO 8601 timestamp | -| `started_at` | `Option` | ISO 8601 timestamp | -| `completed_at` | `Option` | ISO 8601 timestamp | +| Field | Type | Description | +| -------------- | --------------------------- | ----------------------------------------------------------- | +| `job_id` | `Option` | The job ID | +| `state` | `Option` | `pending`, `processing`, `completed`, `failed`, etc. | +| `endpoint` | `Option` | API endpoint that created the job | +| `attempts` | `Option` | Number of execution attempts | +| `error` | `Option` | Error message if failed | +| `response` | `Option` | Full ingestion result (stats, timings, usage) on completion | +| `created_at` | `Option` | ISO 8601 timestamp | +| `started_at` | `Option` | ISO 8601 timestamp | +| `completed_at` | `Option` | ISO 8601 timestamp | Completed response includes ingestion stats (chunk count, entity count, relation count, timings, embedding token usage, and cost in USD). @@ -143,11 +144,11 @@ let res = client.wait_for_ingestion_job( ).await?; ``` -| Parameter | Type | Default | Description | -|-----------|------|---------|-------------| -| `job_id` | `&str` | — | Job to poll | -| `timeout_ms` | `Option` | 30 000 | Max wait in milliseconds | -| `poll_interval_ms` | `Option` | 1 000 | Polling interval | +| Parameter | Type | Default | Description | +| ------------------ | ------------- | ------- | ------------------------ | +| `job_id` | `&str` | — | Job to poll | +| `timeout_ms` | `Option` | 30 000 | Max wait in milliseconds | +| `poll_interval_ms` | `Option` | 1 000 | Polling interval | **Terminal states:** `completed`, `done`, `succeeded`, `success` → returns `Ok`. **Failure states:** `failed`, `error`, `cancelled` → returns `Err`. @@ -173,14 +174,14 @@ let res = client.query_memory(QueryMemoryParams { **`QueryMemoryParams`** (`#[serde(rename_all = "camelCase")]`) -| Field | Type | Serialised as | Description | -|-------|------|---------------|-------------| -| `query` | `String` | `"query"` | The search query | -| `namespace` | `Option` | `"namespace"` | Filter by namespace | -| `include_references` | `Option` | `"includeReferences"` | Include source chunk metadata | -| `max_chunks` | `Option` | `"maxChunks"` | Max chunks to retrieve | -| `document_ids` | `Option>` | `"documentIds"` | Filter to specific documents | -| `llm_query` | `Option` | `"llmQuery"` | Override query sent to LLM | +| Field | Type | Serialised as | Description | +| -------------------- | --------------------- | --------------------- | ----------------------------- | +| `query` | `String` | `"query"` | The search query | +| `namespace` | `Option` | `"namespace"` | Filter by namespace | +| `include_references` | `Option` | `"includeReferences"` | Include source chunk metadata | +| `max_chunks` | `Option` | `"maxChunks"` | Max chunks to retrieve | +| `document_ids` | `Option>` | `"documentIds"` | Filter to specific documents | +| `llm_query` | `Option` | `"llmQuery"` | Override query sent to LLM | **`QueryMemoryResponse`** @@ -225,10 +226,10 @@ let res = client.recall_memory(RecallMemoryParams { **`RecallMemoryParams`** (`#[serde(rename_all = "camelCase")]`) -| Field | Type | Serialised as | Description | -|-------|------|---------------|-------------| -| `namespace` | `Option` | `"namespace"` | Namespace to recall from | -| `max_chunks` | `Option` | `"maxChunks"` | Max chunks to return | +| Field | Type | Serialised as | Description | +| ------------ | ---------------- | ------------- | ------------------------ | +| `namespace` | `Option` | `"namespace"` | Namespace to recall from | +| `max_chunks` | `Option` | `"maxChunks"` | Max chunks to return | **`RecallMemoryResponse`** @@ -297,11 +298,11 @@ let res = client.list_documents(ListDocumentsParams { **`ListDocumentsParams`** -| Field | Type | Description | -|-------|------|-------------| -| `namespace` | `Option` | Filter by namespace | -| `limit` | `Option` | Max results to return | -| `offset` | `Option` | Pagination offset | +| Field | Type | Description | +| ----------- | ---------------- | --------------------- | +| `namespace` | `Option` | Filter by namespace | +| `limit` | `Option` | Max results to return | +| `offset` | `Option` | Pagination offset | Returns `serde_json::Value` with a `data.documents` array. Each document includes `document_id`, `namespace`, `title`, `chunk_count`, `created_at`, `updated_at`, `user_id`. @@ -337,21 +338,21 @@ Both `document_id` and `namespace` are required (validated before the request is ### Other SDK Methods (Available, Not Used in Project) -| Method | Endpoint | Description | -|--------|----------|-------------| -| `insert_document` | `POST /memory/documents` | Insert via documents route | -| `insert_documents_batch` | `POST /memory/documents/batch` | Batch insert documents | -| `recall_memories` | `POST /memory/memories/recall` | Recall from Ebbinghaus bank | -| `recall_memories_context` | `POST /memory/memories/context` | Recall context from memories | -| `recall_thoughts` | `POST /memory/memories/thoughts` | Reflective thought generation | -| `interact_memory` | `POST /memory/interact` | Record entity interactions | -| `record_interactions` | `POST /memory/interactions` | Record interaction signals | -| `query_memory_context` | `POST /memory/queries` | Query alias route | -| `chat_memory_context` | `POST /memory/conversations` | Chat with memory context | -| `chat_memory` | `POST /memory/chat` | Chat via DeltaNet cache | -| `sync_memory` | `POST /memory/sync` | Sync OpenClaw workspace files | -| `memory_health` | `GET /memory/health` | Health check | -| `get_graph_snapshot` | `GET /memory/admin/graph-snapshot` | Admin graph data | +| Method | Endpoint | Description | +| ------------------------- | ---------------------------------- | ----------------------------- | +| `insert_document` | `POST /memory/documents` | Insert via documents route | +| `insert_documents_batch` | `POST /memory/documents/batch` | Batch insert documents | +| `recall_memories` | `POST /memory/memories/recall` | Recall from Ebbinghaus bank | +| `recall_memories_context` | `POST /memory/memories/context` | Recall context from memories | +| `recall_thoughts` | `POST /memory/memories/thoughts` | Reflective thought generation | +| `interact_memory` | `POST /memory/interact` | Record entity interactions | +| `record_interactions` | `POST /memory/interactions` | Record interaction signals | +| `query_memory_context` | `POST /memory/queries` | Query alias route | +| `chat_memory_context` | `POST /memory/conversations` | Chat with memory context | +| `chat_memory` | `POST /memory/chat` | Chat via DeltaNet cache | +| `sync_memory` | `POST /memory/sync` | Sync OpenClaw workspace files | +| `memory_health` | `GET /memory/health` | Health check | +| `get_graph_snapshot` | `GET /memory/admin/graph-snapshot` | Admin graph data | --- @@ -359,12 +360,12 @@ Both `document_id` and `namespace` are required (validated before the request is **`TinyHumansError`** -| Variant | When | -|---------|------| -| `Validation(String)` | Client-side validation failed (empty token, empty title, etc.) | -| `Http(String)` | Network/transport error from `reqwest` | -| `Api { message, status, body }` | Non-2xx response from the API | -| `Decode(String)` | Failed to deserialise response JSON | +| Variant | When | +| ------------------------------- | -------------------------------------------------------------- | +| `Validation(String)` | Client-side validation failed (empty token, empty title, etc.) | +| `Http(String)` | Network/transport error from `reqwest` | +| `Api { message, status, body }` | Non-2xx response from the API | +| `Decode(String)` | Failed to deserialise response JSON | --- @@ -521,28 +522,28 @@ User message: {original message} ### Namespace Conventions -| Context | Namespace pattern | Set by | -|---------|-------------------|--------| -| Skill sync (OAuth / periodic) | `{skill_id}` | `store_skill_sync` — uses `skill_id` directly as namespace | -| Skill memory clear | `{skill_id}` | `clear_skill_memory` | -| Conversation recall | `conversations` | `chat_send_inner` hardcoded | -| Skill context recall (in chat) | `{skill_id}` | `chat_send_inner` per-skill loop | -| E2E test | `sdk-rust-e2e` | `example_e2e.rs` | +| Context | Namespace pattern | Set by | +| ------------------------------ | ----------------- | ---------------------------------------------------------- | +| Skill sync (OAuth / periodic) | `{skill_id}` | `store_skill_sync` — uses `skill_id` directly as namespace | +| Skill memory clear | `{skill_id}` | `clear_skill_memory` | +| Conversation recall | `conversations` | `chat_send_inner` hardcoded | +| Skill context recall (in chat) | `{skill_id}` | `chat_send_inner` per-skill loop | +| E2E test | `sdk-rust-e2e` | `example_e2e.rs` | --- ### All SDK Calls in the Project -| Location | SDK method called | Purpose | -|----------|-------------------|---------| -| `memory/mod.rs::store_skill_sync` | `insert_memory` | Write skill sync data | -| `memory/mod.rs::store_skill_sync` | `ingestion_job_status` (poll loop) | Wait for ingestion to complete | -| `memory/mod.rs::query_skill_context` | `query_memory` | RAG query for skill context | -| `memory/mod.rs::recall_skill_context` | `recall_memory` | Recall synthesised context | -| `memory/mod.rs::recall_namespace_context` | `recall_memory` | Direct namespace recall | -| `memory/mod.rs::query_namespace_context` | `query_memory` | Direct namespace query | -| `memory/mod.rs::list_documents` | `list_documents` | List ingested documents | -| `memory/mod.rs::delete_document` | `delete_document` | Remove a document | -| `memory/mod.rs::clear_skill_memory` | `delete_memory` | Wipe skill namespace on disconnect | -| `commands/chat.rs` (step 2) | via `recall_skill_context` | Inject conversation history into prompt | -| `commands/chat.rs` (step 2b) | via `recall_skill_context` | Inject per-skill context into prompt | +| Location | SDK method called | Purpose | +| ----------------------------------------- | ---------------------------------- | --------------------------------------- | +| `memory/mod.rs::store_skill_sync` | `insert_memory` | Write skill sync data | +| `memory/mod.rs::store_skill_sync` | `ingestion_job_status` (poll loop) | Wait for ingestion to complete | +| `memory/mod.rs::query_skill_context` | `query_memory` | RAG query for skill context | +| `memory/mod.rs::recall_skill_context` | `recall_memory` | Recall synthesised context | +| `memory/mod.rs::recall_namespace_context` | `recall_memory` | Direct namespace recall | +| `memory/mod.rs::query_namespace_context` | `query_memory` | Direct namespace query | +| `memory/mod.rs::list_documents` | `list_documents` | List ingested documents | +| `memory/mod.rs::delete_document` | `delete_document` | Remove a document | +| `memory/mod.rs::clear_skill_memory` | `delete_memory` | Wipe skill namespace on disconnect | +| `commands/chat.rs` (step 2) | via `recall_skill_context` | Inject conversation history into prompt | +| `commands/chat.rs` (step 2b) | via `recall_skill_context` | Inject per-skill context into prompt |