Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/uteke-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ pub enum RoomCommands {
/// Room ID
room_id: String,
},
/// Generate a structured document from room memories
/// Generate a structured document from room memories (API: POST /room/summary)
Document {
/// Room ID
room_id: String,
Expand Down
4 changes: 2 additions & 2 deletions crates/uteke-cli/src/commands/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ pub(crate) fn run(

RoomCommands::Document { room_id } => {
let doc = uteke
.room_document(room_id)
.map_err(|e| format!("Failed to generate room document: {e}"))?
.room_summary_document(room_id)
.map_err(|e| format!("Failed to generate room summary document: {e}"))?
.ok_or_else(|| format!("Room not found: {room_id}"))?;

if cli.json {
Expand Down
2 changes: 1 addition & 1 deletion crates/uteke-cli/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ pub(crate) fn print_aging_preview_human(memories: &[uteke_core::Memory]) {
}
}

/// Print a room document in human-readable format.
/// Print a room summary document in human-readable format.
pub(crate) fn print_room_document_human(doc: &uteke_core::RoomDocument) {
// Header
let title = doc.title.as_deref().unwrap_or(&doc.room_id);
Expand Down
16 changes: 8 additions & 8 deletions crates/uteke-core/src/memory/rooms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ impl super::Store {
/// Returns `None` if the room does not exist.
/// Sections: pinned first, then grouped by type (decision, fact, procedure, preference, context).
/// Empty sections are omitted.
pub fn room_document(&self, room_id: &str) -> Result<Option<RoomDocument>, Error> {
pub fn room_summary_document(&self, room_id: &str) -> Result<Option<RoomDocument>, Error> {
let room = match self.get_room(room_id)? {
Some(r) => r,
None => return Ok(None),
Expand Down Expand Up @@ -1493,22 +1493,22 @@ mod tests {
assert!(summary.is_none());
}

// ── room_document ───────────────────────────────────────────
// ── room_summary_document ───────────────────────────────────────────

#[test]
fn room_document_empty_room() {
fn room_summary_document_empty_room() {
let store = Store::open(":memory:").unwrap();
store
.create_room("doc-empty", Some("Doc Empty"), "default")
.unwrap();

let doc = store.room_document("doc-empty").unwrap().unwrap();
let doc = store.room_summary_document("doc-empty").unwrap().unwrap();
assert_eq!(doc.room_id, "doc-empty");
assert!(doc.sections.is_empty());
}

#[test]
fn room_document_with_memories() {
fn room_summary_document_with_memories() {
let store = Store::open(":memory:").unwrap();
store
.create_room("doc-room", Some("Doc Room"), "default")
Expand All @@ -1533,7 +1533,7 @@ mod tests {
.link_memory_to_room("doc-room", "mem-doc3", "alice", "lead")
.unwrap();

let doc = store.room_document("doc-room").unwrap().unwrap();
let doc = store.room_summary_document("doc-room").unwrap().unwrap();
assert_eq!(doc.room_id, "doc-room");
assert!(doc.sections.len() >= 2);

Expand All @@ -1543,9 +1543,9 @@ mod tests {
}

#[test]
fn room_document_nonexistent_returns_none() {
fn room_summary_document_nonexistent_returns_none() {
let store = Store::open(":memory:").unwrap();
let doc = store.room_document("nope").unwrap();
let doc = store.room_summary_document("nope").unwrap();
assert!(doc.is_none());
}

Expand Down
13 changes: 7 additions & 6 deletions crates/uteke-core/src/rooms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,10 @@ impl crate::Uteke {
self.store.room_summary_with_docs(room_id)
}

/// Generate a structured document from room memories.
pub fn room_document(&self, room_id: &str) -> Result<Option<RoomDocument>, Error> {
self.store.room_document(room_id)
/// Generate a structured summary document from room memories.
/// API endpoint: POST /room/summary (#735)
pub fn room_summary_document(&self, room_id: &str) -> Result<Option<RoomDocument>, Error> {
self.store.room_summary_document(room_id)
}

// ── Room ↔ Document junction (v15, #689) ─────────────────────────────
Expand Down Expand Up @@ -275,7 +276,7 @@ mod tests {
.unwrap();

// Empty room → no sections
let doc = uteke.room_document("doc-room").unwrap().unwrap();
let doc = uteke.room_summary_document("doc-room").unwrap().unwrap();
assert!(doc.sections.is_empty());
}

Expand All @@ -287,14 +288,14 @@ mod tests {
.remember_in_room("Some fact", &[], None, None, "fact", "doc-room", "bob")
.unwrap();

let doc = uteke.room_document("doc-room").unwrap().unwrap();
let doc = uteke.room_summary_document("doc-room").unwrap().unwrap();
assert_eq!(doc.room_id, "doc-room");
assert_eq!(doc.sections.len(), 1); // Research & Facts
}
#[test]
fn room_document_nonexistent_returns_none() {
let uteke = open_in_memory();
assert!(uteke.room_document("nope").unwrap().is_none());
assert!(uteke.room_summary_document("nope").unwrap().is_none());
}

// ── Room ↔ Document junction ──────────────────────────────────
Expand Down
2 changes: 1 addition & 1 deletion crates/uteke-mcp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,7 @@ fn exec_room_document(uteke: &Uteke, args: &Value) -> Result<ToolResult, String>
let room_id = args["room_id"].as_str().ok_or("Missing 'room_id'")?;

let doc = uteke
.room_document(room_id)
.room_summary_document(room_id)
.map_err(|e| format!("Failed: {e}"))?;

let doc = match doc {
Expand Down
32 changes: 28 additions & 4 deletions crates/uteke-server/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use serde::Deserialize;
use tiny_http::{Header, Method, Request, Response, StatusCode};
use tracing::error;
use tracing::{error, warn};

use uteke_core::Uteke;

Expand Down Expand Up @@ -57,7 +57,7 @@
"/stats",
"/room/recall",
"/room/summary",
"/room/document",
"/room/summary-document",

Check failure

Code scanning / CodeCora

Allowlist drops /room/document while deprecated handler still routes it Error

The path allowlist replaced /room/document with /room/summary-document ("/room/document" -> "/room/summary-document"). However, the deprecated handler (Method::Post, "/room/document") is still kept below for backward compatibility (with a warn! log). If this allowlist is used to gate requests (e.g., CORS preflight allow list or method dispatch filter), then clients still calling the old POST /room/document endpoint will be rejected before reaching the deprecated handler, silently breaking backward compatibility. The deprecated route is effectively dead code. Verify how the allowlist is consumed; if it gates routing, /room/document must remain in the list during the deprecation window.
"/room/stats",
"/room/document/list",
"/doc/get",
Expand Down Expand Up @@ -646,14 +646,38 @@
}
}

// ── Room Document ────────────────────────────────────────────────
// ── Room Summary Document ────────────────────────────────────────
(Method::Post, "/room/summary-document") => {
#[derive(Deserialize)]
struct RoomSummaryDocumentRequest {
room_id: String,
}
match read_body::<RoomSummaryDocumentRequest>(req.as_reader()) {
Ok(req_data) => match uteke.room_summary_document(&req_data.room_id) {
Ok(Some(doc)) => ctx.ok_response_for(req, &doc),
Ok(None) => ctx.error_response_for(
req,
404,
format!("Room not found: {}", req_data.room_id),
),
Err(e) => {
error!("Internal error: {e}");
ctx.error_response_for(req, 500, "Internal server error")
}
},
Err(e) => ctx.error_response_for(req, 400, e),
}
}

// ── DEPRECATED: POST /room/document → /room/summary-document (#735)
(Method::Post, "/room/document") => {
warn!("DEPRECATED: POST /room/document is renamed to POST /room/summary-document (see #735)");
#[derive(Deserialize)]
struct RoomDocumentRequest {
room_id: String,
}
match read_body::<RoomDocumentRequest>(req.as_reader()) {
Ok(req_data) => match uteke.room_document(&req_data.room_id) {
Ok(req_data) => match uteke.room_summary_document(&req_data.room_id) {
Ok(Some(doc)) => ctx.ok_response_for(req, &doc),
Ok(None) => ctx.error_response_for(
req,
Expand Down
2 changes: 1 addition & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ When `[server] enabled = true` is set in config, the CLI auto-routes commands th
| GET | `/room/list` | List rooms (supports `?namespace=`) |
| POST | `/room/recall` | Recall from a room |
| POST | `/room/summary` | Room summary |
| POST | `/room/document` | Generate document from room |
| POST | `/room/summary-document` | Generate summary document from room (#735) |
| POST | `/room/stats` | Room statistics |
| DELETE | `/room/delete` | Delete a room |
| POST | `/room/document/list` | List documents linked to a room (#689) |
Expand Down
2 changes: 1 addition & 1 deletion docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ Both transports expose the same tools (MCP protocol version `2025-06-18`):
| `uteke_room_delete` | Delete a room |
| `uteke_room_stats` | Room statistics |
| `uteke_room_summary` | Room topic summary (tag clustering, no LLM) |
| `uteke_room_document` | Generate structured document from room |
| `uteke_room_document` | Generate summary document from room (→ `POST /room/summary-document`) |
| `uteke_tags_list` | List all tags with counts (#566) |
| `uteke_tags_rename` | Rename a tag across all memories (#566) |
| `uteke_tags_delete` | Delete a tag from all memories (#566) |
Expand Down
2 changes: 1 addition & 1 deletion docs/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Both transports expose the same 29 tools (MCP protocol version `2025-06-18`):
| `uteke_room_delete` | Delete a room |
| `uteke_room_stats` | Room statistics |
| `uteke_room_summary` | Room topic summary (tag clustering, no LLM) |
| `uteke_room_document` | Generate structured document from room |
| `uteke_room_document` | Generate summary document from room (→ `POST /room/summary-document`) |
| `uteke_tags_list` | List all tags with counts (#566) |
| `uteke_tags_rename` | Rename a tag across all memories (#566) |
| `uteke_tags_delete` | Delete a tag from all memories (#566) |
Expand Down
2 changes: 2 additions & 0 deletions docs/rooms.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ uteke room recall "project-kickoff" --query "database decision"

Combine room memories into a cohesive document:

> **Note:** The CLI command remains `uteke room document`, but the underlying HTTP API route has been renamed from `POST /room/document` to `POST /room/summary-document`.

```bash
uteke room document "project-kickoff"
```
Expand Down