summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-10 23:29:43 +0000
committersoryu <soryu@soryu.co>2026-02-10 23:29:43 +0000
commit94ab62cf87fe7f0e941328096b566accd2aba645 (patch)
treeb533e33de3c2c6314f11c8a81cb954f6e25aea47
parent339c1769379a851c4126021132573bd4b7994cf2 (diff)
downloadsoryu-makima/makima--add-an-optional-memory-system-for-directiv-69115736.tar.gz
soryu-makima/makima--add-an-optional-memory-system-for-directiv-69115736.zip
-rw-r--r--makima/migrations/20260211000000_create_directive_memories.sql16
-rw-r--r--makima/src/db/models.rs41
-rw-r--r--makima/src/db/repository.rs132
-rw-r--r--makima/src/server/handlers/directives.rs395
-rw-r--r--makima/src/server/mod.rs4
-rw-r--r--makima/src/server/openapi.rs21
6 files changed, 597 insertions, 12 deletions
diff --git a/makima/migrations/20260211000000_create_directive_memories.sql b/makima/migrations/20260211000000_create_directive_memories.sql
new file mode 100644
index 0000000..5aae339
--- /dev/null
+++ b/makima/migrations/20260211000000_create_directive_memories.sql
@@ -0,0 +1,16 @@
+-- Directive memory system: persistent key-value storage for directives.
+-- Allows directives to store and retrieve context across sessions.
+
+CREATE TABLE directive_memories (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ directive_id UUID NOT NULL REFERENCES directives(id) ON DELETE CASCADE,
+ key VARCHAR(255) NOT NULL,
+ value TEXT NOT NULL,
+ category VARCHAR(100),
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
+ UNIQUE (directive_id, key)
+);
+
+CREATE INDEX idx_directive_memories_directive_id ON directive_memories(directive_id);
+CREATE INDEX idx_directive_memories_category ON directive_memories(directive_id, category);
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 9159fd5..ec96b27 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -2833,3 +2833,44 @@ pub struct UpdateDirectiveStepRequest {
pub task_id: Option<Uuid>,
pub order_index: Option<i32>,
}
+
+// =============================================================================
+// Directive Memory Types
+// =============================================================================
+
+/// A memory entry for a directive — persistent key-value storage.
+#[derive(Debug, Clone, FromRow, Serialize, Deserialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct DirectiveMemory {
+ pub id: Uuid,
+ pub directive_id: Uuid,
+ pub key: String,
+ pub value: String,
+ pub category: Option<String>,
+ pub created_at: DateTime<Utc>,
+ pub updated_at: DateTime<Utc>,
+}
+
+/// Request to set (upsert) a single directive memory entry.
+#[derive(Debug, Deserialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct SetDirectiveMemoryRequest {
+ pub key: String,
+ pub value: String,
+ pub category: Option<String>,
+}
+
+/// Request to batch set multiple directive memory entries.
+#[derive(Debug, Deserialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct BatchSetDirectiveMemoryRequest {
+ pub memories: Vec<SetDirectiveMemoryRequest>,
+}
+
+/// Response for listing directive memories.
+#[derive(Debug, Serialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct DirectiveMemoryListResponse {
+ pub memories: Vec<DirectiveMemory>,
+ pub total: i64,
+}
diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs
index 930a73e..1b058e7 100644
--- a/makima/src/db/repository.rs
+++ b/makima/src/db/repository.rs
@@ -11,9 +11,9 @@ use super::models::{
ContractTypeTemplateRecord, ConversationMessage, ConversationSnapshot,
CreateContractRequest, CreateFileRequest, CreateTaskRequest,
CreateTemplateRequest, Daemon, DaemonTaskAssignment, DaemonWithCapacity,
- DeliverableDefinition, Directive, DirectiveStep, DirectiveSummary,
- CreateDirectiveRequest, CreateDirectiveStepRequest, UpdateDirectiveRequest,
- UpdateDirectiveStepRequest,
+ DeliverableDefinition, Directive, DirectiveMemory, DirectiveStep, DirectiveSummary,
+ CreateDirectiveRequest, CreateDirectiveStepRequest, SetDirectiveMemoryRequest,
+ UpdateDirectiveRequest, UpdateDirectiveStepRequest,
File, FileSummary, FileVersion, HistoryEvent, HistoryQueryFilters,
MeshChatConversation, MeshChatMessageRecord, PhaseChangeResult, PhaseConfig,
PhaseDefinition, SupervisorHeartbeatRecord, SupervisorState,
@@ -5612,3 +5612,129 @@ pub async fn get_directive_max_generation(
.await?;
Ok(row.0.unwrap_or(0))
}
+
+// =============================================================================
+// Directive Memory CRUD
+// =============================================================================
+
+/// List all memories for a directive, optionally filtered by category.
+pub async fn list_directive_memories(
+ pool: &PgPool,
+ directive_id: Uuid,
+ category: Option<&str>,
+) -> Result<Vec<DirectiveMemory>, sqlx::Error> {
+ match category {
+ Some(cat) => {
+ sqlx::query_as::<_, DirectiveMemory>(
+ r#"
+ SELECT * FROM directive_memories
+ WHERE directive_id = $1 AND category = $2
+ ORDER BY key
+ "#,
+ )
+ .bind(directive_id)
+ .bind(cat)
+ .fetch_all(pool)
+ .await
+ }
+ None => {
+ sqlx::query_as::<_, DirectiveMemory>(
+ r#"
+ SELECT * FROM directive_memories
+ WHERE directive_id = $1
+ ORDER BY key
+ "#,
+ )
+ .bind(directive_id)
+ .fetch_all(pool)
+ .await
+ }
+ }
+}
+
+/// Get a single memory entry by directive ID and key.
+pub async fn get_directive_memory(
+ pool: &PgPool,
+ directive_id: Uuid,
+ key: &str,
+) -> Result<Option<DirectiveMemory>, sqlx::Error> {
+ sqlx::query_as::<_, DirectiveMemory>(
+ r#"
+ SELECT * FROM directive_memories
+ WHERE directive_id = $1 AND key = $2
+ "#,
+ )
+ .bind(directive_id)
+ .bind(key)
+ .fetch_optional(pool)
+ .await
+}
+
+/// Set (upsert) a single memory entry for a directive.
+pub async fn set_directive_memory(
+ pool: &PgPool,
+ directive_id: Uuid,
+ req: &SetDirectiveMemoryRequest,
+) -> Result<DirectiveMemory, sqlx::Error> {
+ sqlx::query_as::<_, DirectiveMemory>(
+ r#"
+ INSERT INTO directive_memories (directive_id, key, value, category)
+ VALUES ($1, $2, $3, $4)
+ ON CONFLICT (directive_id, key)
+ DO UPDATE SET value = EXCLUDED.value,
+ category = EXCLUDED.category,
+ updated_at = NOW()
+ RETURNING *
+ "#,
+ )
+ .bind(directive_id)
+ .bind(&req.key)
+ .bind(&req.value)
+ .bind(&req.category)
+ .fetch_one(pool)
+ .await
+}
+
+/// Batch set multiple memory entries for a directive.
+pub async fn batch_set_directive_memories(
+ pool: &PgPool,
+ directive_id: Uuid,
+ memories: &[SetDirectiveMemoryRequest],
+) -> Result<Vec<DirectiveMemory>, sqlx::Error> {
+ let mut results = Vec::with_capacity(memories.len());
+ for mem in memories {
+ let result = set_directive_memory(pool, directive_id, mem).await?;
+ results.push(result);
+ }
+ Ok(results)
+}
+
+/// Delete a single memory entry by directive ID and key.
+pub async fn delete_directive_memory(
+ pool: &PgPool,
+ directive_id: Uuid,
+ key: &str,
+) -> Result<bool, sqlx::Error> {
+ let result = sqlx::query(
+ r#"DELETE FROM directive_memories WHERE directive_id = $1 AND key = $2"#,
+ )
+ .bind(directive_id)
+ .bind(key)
+ .execute(pool)
+ .await?;
+ Ok(result.rows_affected() > 0)
+}
+
+/// Clear all memory entries for a directive.
+pub async fn clear_directive_memories(
+ pool: &PgPool,
+ directive_id: Uuid,
+) -> Result<u64, sqlx::Error> {
+ let result = sqlx::query(
+ r#"DELETE FROM directive_memories WHERE directive_id = $1"#,
+ )
+ .bind(directive_id)
+ .execute(pool)
+ .await?;
+ Ok(result.rows_affected())
+}
diff --git a/makima/src/server/handlers/directives.rs b/makima/src/server/handlers/directives.rs
index d48ff74..f624d82 100644
--- a/makima/src/server/handlers/directives.rs
+++ b/makima/src/server/handlers/directives.rs
@@ -1,23 +1,31 @@
//! HTTP handlers for directive CRUD and DAG progression.
use axum::{
- extract::{Path, State},
+ extract::{Path, Query, State},
http::StatusCode,
response::IntoResponse,
Json,
};
+use serde::Deserialize;
use uuid::Uuid;
use crate::db::models::{
- CreateDirectiveRequest, CreateDirectiveStepRequest, Directive, DirectiveListResponse,
- DirectiveStep, DirectiveWithSteps, UpdateDirectiveRequest, UpdateDirectiveStepRequest,
- UpdateGoalRequest,
+ BatchSetDirectiveMemoryRequest, CreateDirectiveRequest, CreateDirectiveStepRequest,
+ Directive, DirectiveListResponse, DirectiveMemory, DirectiveMemoryListResponse,
+ DirectiveStep, DirectiveWithSteps, SetDirectiveMemoryRequest, UpdateDirectiveRequest,
+ UpdateDirectiveStepRequest, UpdateGoalRequest,
};
use crate::db::repository;
use crate::server::auth::Authenticated;
use crate::server::messages::ApiError;
use crate::server::state::SharedState;
+/// Query parameters for the memory list endpoint.
+#[derive(Debug, Deserialize)]
+pub struct MemoryListQuery {
+ pub category: Option<String>,
+}
+
// =============================================================================
// Directive CRUD
// =============================================================================
@@ -839,3 +847,382 @@ pub async fn update_goal(
}
}
}
+
+// =============================================================================
+// Directive Memory CRUD
+// =============================================================================
+
+/// List all memories for a directive, optionally filtered by category.
+#[utoipa::path(
+ get,
+ path = "/api/v1/directives/{id}/memories",
+ params(
+ ("id" = Uuid, Path, description = "Directive ID"),
+ ("category" = Option<String>, Query, description = "Filter by category"),
+ ),
+ responses(
+ (status = 200, description = "List of memories", body = DirectiveMemoryListResponse),
+ (status = 404, description = "Directive not found", body = ApiError),
+ (status = 503, description = "Database not configured", body = ApiError),
+ ),
+ security(("bearer_auth" = []), ("api_key" = [])),
+ tag = "Directives"
+)]
+pub async fn list_memories(
+ State(state): State<SharedState>,
+ Authenticated(auth): Authenticated,
+ Path(id): Path<Uuid>,
+ Query(query): Query<MemoryListQuery>,
+) -> impl IntoResponse {
+ let Some(ref pool) = state.db_pool else {
+ return (
+ StatusCode::SERVICE_UNAVAILABLE,
+ Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
+ )
+ .into_response();
+ };
+
+ // Verify directive ownership
+ match repository::get_directive_for_owner(pool, auth.owner_id, id).await {
+ Ok(Some(_)) => {}
+ Ok(None) => {
+ return (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Directive not found")),
+ )
+ .into_response();
+ }
+ Err(e) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response();
+ }
+ }
+
+ match repository::list_directive_memories(pool, id, query.category.as_deref()).await {
+ Ok(memories) => {
+ let total = memories.len() as i64;
+ Json(DirectiveMemoryListResponse { memories, total }).into_response()
+ }
+ Err(e) => {
+ tracing::error!("Failed to list memories: {}", e);
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("LIST_FAILED", &e.to_string())),
+ )
+ .into_response()
+ }
+ }
+}
+
+/// Get a single memory entry by key.
+#[utoipa::path(
+ get,
+ path = "/api/v1/directives/{id}/memories/{key}",
+ params(
+ ("id" = Uuid, Path, description = "Directive ID"),
+ ("key" = String, Path, description = "Memory key"),
+ ),
+ responses(
+ (status = 200, description = "Memory entry", body = DirectiveMemory),
+ (status = 404, description = "Not found", body = ApiError),
+ (status = 503, description = "Database not configured", body = ApiError),
+ ),
+ security(("bearer_auth" = []), ("api_key" = [])),
+ tag = "Directives"
+)]
+pub async fn get_memory(
+ State(state): State<SharedState>,
+ Authenticated(auth): Authenticated,
+ Path((id, key)): Path<(Uuid, String)>,
+) -> impl IntoResponse {
+ let Some(ref pool) = state.db_pool else {
+ return (
+ StatusCode::SERVICE_UNAVAILABLE,
+ Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
+ )
+ .into_response();
+ };
+
+ // Verify directive ownership
+ match repository::get_directive_for_owner(pool, auth.owner_id, id).await {
+ Ok(Some(_)) => {}
+ Ok(None) => {
+ return (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Directive not found")),
+ )
+ .into_response();
+ }
+ Err(e) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response();
+ }
+ }
+
+ match repository::get_directive_memory(pool, id, &key).await {
+ Ok(Some(memory)) => Json(memory).into_response(),
+ Ok(None) => (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Memory entry not found")),
+ )
+ .into_response(),
+ Err(e) => {
+ tracing::error!("Failed to get memory: {}", e);
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response()
+ }
+ }
+}
+
+/// Set (upsert) a single memory entry.
+#[utoipa::path(
+ post,
+ path = "/api/v1/directives/{id}/memories",
+ params(("id" = Uuid, Path, description = "Directive ID")),
+ request_body = SetDirectiveMemoryRequest,
+ responses(
+ (status = 200, description = "Memory entry set", body = DirectiveMemory),
+ (status = 404, description = "Directive not found", body = ApiError),
+ (status = 503, description = "Database not configured", body = ApiError),
+ ),
+ security(("bearer_auth" = []), ("api_key" = [])),
+ tag = "Directives"
+)]
+pub async fn set_memory(
+ State(state): State<SharedState>,
+ Authenticated(auth): Authenticated,
+ Path(id): Path<Uuid>,
+ Json(req): Json<SetDirectiveMemoryRequest>,
+) -> impl IntoResponse {
+ let Some(ref pool) = state.db_pool else {
+ return (
+ StatusCode::SERVICE_UNAVAILABLE,
+ Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
+ )
+ .into_response();
+ };
+
+ // Verify directive ownership
+ match repository::get_directive_for_owner(pool, auth.owner_id, id).await {
+ Ok(Some(_)) => {}
+ Ok(None) => {
+ return (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Directive not found")),
+ )
+ .into_response();
+ }
+ Err(e) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response();
+ }
+ }
+
+ match repository::set_directive_memory(pool, id, &req).await {
+ Ok(memory) => Json(memory).into_response(),
+ Err(e) => {
+ tracing::error!("Failed to set memory: {}", e);
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("SET_FAILED", &e.to_string())),
+ )
+ .into_response()
+ }
+ }
+}
+
+/// Batch set multiple memory entries.
+#[utoipa::path(
+ post,
+ path = "/api/v1/directives/{id}/memories/batch",
+ params(("id" = Uuid, Path, description = "Directive ID")),
+ request_body = BatchSetDirectiveMemoryRequest,
+ responses(
+ (status = 200, description = "Memory entries set", body = Vec<DirectiveMemory>),
+ (status = 404, description = "Directive not found", body = ApiError),
+ (status = 503, description = "Database not configured", body = ApiError),
+ ),
+ security(("bearer_auth" = []), ("api_key" = [])),
+ tag = "Directives"
+)]
+pub async fn batch_set_memories(
+ State(state): State<SharedState>,
+ Authenticated(auth): Authenticated,
+ Path(id): Path<Uuid>,
+ Json(req): Json<BatchSetDirectiveMemoryRequest>,
+) -> impl IntoResponse {
+ let Some(ref pool) = state.db_pool else {
+ return (
+ StatusCode::SERVICE_UNAVAILABLE,
+ Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
+ )
+ .into_response();
+ };
+
+ // Verify directive ownership
+ match repository::get_directive_for_owner(pool, auth.owner_id, id).await {
+ Ok(Some(_)) => {}
+ Ok(None) => {
+ return (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Directive not found")),
+ )
+ .into_response();
+ }
+ Err(e) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response();
+ }
+ }
+
+ match repository::batch_set_directive_memories(pool, id, &req.memories).await {
+ Ok(memories) => Json(memories).into_response(),
+ Err(e) => {
+ tracing::error!("Failed to batch set memories: {}", e);
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("SET_FAILED", &e.to_string())),
+ )
+ .into_response()
+ }
+ }
+}
+
+/// Delete a single memory entry by key.
+#[utoipa::path(
+ delete,
+ path = "/api/v1/directives/{id}/memories/{key}",
+ params(
+ ("id" = Uuid, Path, description = "Directive ID"),
+ ("key" = String, Path, description = "Memory key"),
+ ),
+ responses(
+ (status = 204, description = "Deleted"),
+ (status = 404, description = "Not found", body = ApiError),
+ (status = 503, description = "Database not configured", body = ApiError),
+ ),
+ security(("bearer_auth" = []), ("api_key" = [])),
+ tag = "Directives"
+)]
+pub async fn delete_memory(
+ State(state): State<SharedState>,
+ Authenticated(auth): Authenticated,
+ Path((id, key)): Path<(Uuid, String)>,
+) -> impl IntoResponse {
+ let Some(ref pool) = state.db_pool else {
+ return (
+ StatusCode::SERVICE_UNAVAILABLE,
+ Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
+ )
+ .into_response();
+ };
+
+ // Verify directive ownership
+ match repository::get_directive_for_owner(pool, auth.owner_id, id).await {
+ Ok(Some(_)) => {}
+ Ok(None) => {
+ return (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Directive not found")),
+ )
+ .into_response();
+ }
+ Err(e) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response();
+ }
+ }
+
+ match repository::delete_directive_memory(pool, id, &key).await {
+ Ok(true) => StatusCode::NO_CONTENT.into_response(),
+ Ok(false) => (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Memory entry not found")),
+ )
+ .into_response(),
+ Err(e) => {
+ tracing::error!("Failed to delete memory: {}", e);
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("DELETE_FAILED", &e.to_string())),
+ )
+ .into_response()
+ }
+ }
+}
+
+/// Clear all memories for a directive.
+#[utoipa::path(
+ delete,
+ path = "/api/v1/directives/{id}/memories",
+ params(("id" = Uuid, Path, description = "Directive ID")),
+ responses(
+ (status = 204, description = "All memories cleared"),
+ (status = 404, description = "Directive not found", body = ApiError),
+ (status = 503, description = "Database not configured", body = ApiError),
+ ),
+ security(("bearer_auth" = []), ("api_key" = [])),
+ tag = "Directives"
+)]
+pub async fn clear_memories(
+ State(state): State<SharedState>,
+ Authenticated(auth): Authenticated,
+ Path(id): Path<Uuid>,
+) -> impl IntoResponse {
+ let Some(ref pool) = state.db_pool else {
+ return (
+ StatusCode::SERVICE_UNAVAILABLE,
+ Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
+ )
+ .into_response();
+ };
+
+ // Verify directive ownership
+ match repository::get_directive_for_owner(pool, auth.owner_id, id).await {
+ Ok(Some(_)) => {}
+ Ok(None) => {
+ return (
+ StatusCode::NOT_FOUND,
+ Json(ApiError::new("NOT_FOUND", "Directive not found")),
+ )
+ .into_response();
+ }
+ Err(e) => {
+ return (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("GET_FAILED", &e.to_string())),
+ )
+ .into_response();
+ }
+ }
+
+ match repository::clear_directive_memories(pool, id).await {
+ Ok(_) => StatusCode::NO_CONTENT.into_response(),
+ Err(e) => {
+ tracing::error!("Failed to clear memories: {}", e);
+ (
+ StatusCode::INTERNAL_SERVER_ERROR,
+ Json(ApiError::new("CLEAR_FAILED", &e.to_string())),
+ )
+ .into_response()
+ }
+ }
+}
diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs
index 4cb4296..b380508 100644
--- a/makima/src/server/mod.rs
+++ b/makima/src/server/mod.rs
@@ -237,6 +237,10 @@ pub fn make_router(state: SharedState) -> Router {
.route("/directives/{id}/steps/{step_id}/fail", post(directives::fail_step))
.route("/directives/{id}/steps/{step_id}/skip", post(directives::skip_step))
.route("/directives/{id}/goal", put(directives::update_goal))
+ // Directive memory endpoints
+ .route("/directives/{id}/memories", get(directives::list_memories).post(directives::set_memory).delete(directives::clear_memories))
+ .route("/directives/{id}/memories/batch", post(directives::batch_set_memories))
+ .route("/directives/{id}/memories/{key}", get(directives::get_memory).delete(directives::delete_memory))
// Timeline endpoint (unified history for user)
.route("/timeline", get(history::get_timeline))
// Contract type templates (built-in only)
diff --git a/makima/src/server/openapi.rs b/makima/src/server/openapi.rs
index ddc2db5..f049759 100644
--- a/makima/src/server/openapi.rs
+++ b/makima/src/server/openapi.rs
@@ -3,21 +3,21 @@
use utoipa::OpenApi;
use crate::db::models::{
- AddLocalRepositoryRequest, AddRemoteRepositoryRequest, BranchInfo, BranchListResponse,
- BranchTaskRequest, BranchTaskResponse,
+ AddLocalRepositoryRequest, AddRemoteRepositoryRequest, BatchSetDirectiveMemoryRequest,
+ BranchInfo, BranchListResponse, BranchTaskRequest, BranchTaskResponse,
ChangePhaseRequest,
Contract, ContractChatHistoryResponse, ContractChatMessageRecord, ContractEvent,
ContractListResponse, ContractRepository, ContractSummary, ContractWithRelations,
CreateContractRequest, CreateDirectiveRequest, CreateDirectiveStepRequest, CreateFileRequest,
CreateManagedRepositoryRequest, CreateTaskRequest, Daemon, DaemonDirectoriesResponse,
- DaemonDirectory, DaemonListResponse, Directive, DirectiveListResponse, DirectiveStep,
- DirectiveSummary, DirectiveWithSteps,
+ DaemonDirectory, DaemonListResponse, Directive, DirectiveListResponse, DirectiveMemory,
+ DirectiveMemoryListResponse, DirectiveStep, DirectiveSummary, DirectiveWithSteps,
File, FileListResponse, FileSummary,
MergeCommitRequest, MergeCompleteCheckResponse, MergeResolveRequest, MergeResultResponse,
MergeSkipRequest, MergeStartRequest, MergeStatusResponse, MeshChatConversation,
MeshChatHistoryResponse, MeshChatMessageRecord, RepositoryHistoryEntry,
RepositoryHistoryListResponse, RepositorySuggestionsQuery, SendMessageRequest,
- Task,
+ SetDirectiveMemoryRequest, Task,
TaskEventListResponse, TaskListResponse, TaskSummary, TaskWithSubtasks, TranscriptEntry,
UpdateContractRequest, UpdateDirectiveRequest, UpdateDirectiveStepRequest,
UpdateFileRequest, UpdateGoalRequest, UpdateTaskRequest,
@@ -123,6 +123,13 @@ use crate::server::messages::{ApiError, AudioEncoding, StartMessage, StopMessage
directives::fail_step,
directives::skip_step,
directives::update_goal,
+ // Directive memory endpoints
+ directives::list_memories,
+ directives::get_memory,
+ directives::set_memory,
+ directives::batch_set_memories,
+ directives::delete_memory,
+ directives::clear_memories,
// Repository history/settings endpoints
repository_history::list_repository_history,
repository_history::get_repository_suggestions,
@@ -219,6 +226,10 @@ use crate::server::messages::{ApiError, AudioEncoding, StartMessage, StopMessage
UpdateGoalRequest,
CreateDirectiveStepRequest,
UpdateDirectiveStepRequest,
+ DirectiveMemory,
+ DirectiveMemoryListResponse,
+ SetDirectiveMemoryRequest,
+ BatchSetDirectiveMemoryRequest,
// Repository history schemas
RepositoryHistoryEntry,
RepositoryHistoryListResponse,