feat(gateway): PUT/DELETE /api/memories/{key} write endpoints
This commit is contained in:
parent
3f09793864
commit
b49f0ec8a5
@ -947,6 +947,49 @@ pub async fn get_memories(
|
|||||||
Ok(Json(json!({ "memories": memories })))
|
Ok(Json(json!({ "memories": memories })))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct PutMemoryBody {
|
||||||
|
content: String,
|
||||||
|
importance: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn put_memory(
|
||||||
|
State(state): State<Arc<GatewayState>>,
|
||||||
|
Path(key): Path<String>,
|
||||||
|
Json(body): Json<PutMemoryBody>,
|
||||||
|
) -> Result<Json<Value>, ApiError> {
|
||||||
|
let existing = state
|
||||||
|
.storage
|
||||||
|
.get_memory_by_key(&key)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::internal)?
|
||||||
|
.ok_or_else(|| ApiError::not_found("memory not found"))?;
|
||||||
|
let mut updated = existing;
|
||||||
|
updated.content = body.content;
|
||||||
|
if let Some(importance) = body.importance {
|
||||||
|
updated.importance = importance.clamp(0.0, 1.0);
|
||||||
|
}
|
||||||
|
updated.updated_at = chrono::Utc::now().to_rfc3339();
|
||||||
|
state
|
||||||
|
.storage
|
||||||
|
.upsert_memory(&updated)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::internal)?;
|
||||||
|
Ok(Json(json!({ "updated": true, "key": key })))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_memory(
|
||||||
|
State(state): State<Arc<GatewayState>>,
|
||||||
|
Path(key): Path<String>,
|
||||||
|
) -> Result<Json<Value>, ApiError> {
|
||||||
|
state
|
||||||
|
.storage
|
||||||
|
.delete_memory(&key)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::internal)?;
|
||||||
|
Ok(Json(json!({ "deleted": true })))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -599,6 +599,10 @@ fn build_router(state: Arc<GatewayState>) -> Router {
|
|||||||
.route("/api/jobs", routing::get(http::get_jobs))
|
.route("/api/jobs", routing::get(http::get_jobs))
|
||||||
.route("/api/jobs/{id}/runs", routing::get(http::get_job_runs))
|
.route("/api/jobs/{id}/runs", routing::get(http::get_job_runs))
|
||||||
.route("/api/memories", routing::get(http::get_memories))
|
.route("/api/memories", routing::get(http::get_memories))
|
||||||
|
.route(
|
||||||
|
"/api/memories/{key}",
|
||||||
|
routing::put(http::put_memory).delete(http::delete_memory),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/chat/{client_id}/uploads",
|
"/api/chat/{client_id}/uploads",
|
||||||
routing::post(http::upload_file).layer(axum::extract::DefaultBodyLimit::disable()),
|
routing::post(http::upload_file).layer(axum::extract::DefaultBodyLimit::disable()),
|
||||||
|
|||||||
@ -42,6 +42,17 @@ impl super::Storage {
|
|||||||
parse_memory_rows(&rows)
|
parse_memory_rows(&rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_memory_by_key(&self, key: &str) -> Result<Option<MemoryEntry>, StorageError> {
|
||||||
|
let rows = sqlx::query(
|
||||||
|
"SELECT id, key, content, category, importance, session_id, created_at, updated_at FROM memories WHERE key = ?",
|
||||||
|
)
|
||||||
|
.bind(key)
|
||||||
|
.fetch_all(self.pool())
|
||||||
|
.await?;
|
||||||
|
let mut entries = parse_memory_rows(&rows)?;
|
||||||
|
Ok(entries.pop())
|
||||||
|
}
|
||||||
|
|
||||||
/// Store or update a memory entry (upsert by key).
|
/// Store or update a memory entry (upsert by key).
|
||||||
pub async fn upsert_memory(&self, entry: &MemoryEntry) -> Result<(), StorageError> {
|
pub async fn upsert_memory(&self, entry: &MemoryEntry) -> Result<(), StorageError> {
|
||||||
let category_str = entry.category.as_str();
|
let category_str = entry.category.as_str();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user