feat(memory-config): Add V1 memory config management API endpoints
-Add full CRUD endpoints for memory config via API Key auth (/v1/memory_config) -Add V1 request schemas: ConfigCreateRequest, ConfigUpdateRequest, ConfigUpdateExtractedRequest, ConfigUpdateForgettingRequest -Add config-workspace ownership verification -Add scenes/simple, read_all_config, read_config_extracted query endpoints -Add create_config, update_config, update_config_extracted, update_config_forgetting, delete_config mutation endpoints -Reuse management-side controllers with pre-validation ownership checks
This commit is contained in:
@@ -4,9 +4,10 @@ This module defines Pydantic schemas for the Memory API Service endpoints,
|
||||
including request validation and response structures for read and write operations.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
class MemoryWriteRequest(BaseModel):
|
||||
@@ -231,6 +232,7 @@ class MemoryConfigItem(BaseModel):
|
||||
created_at: Optional[str] = Field(None, description="Creation timestamp")
|
||||
updated_at: Optional[str] = Field(None, description="Last update timestamp")
|
||||
|
||||
# ========== V1 记忆配置管理接口 Schema ==========
|
||||
|
||||
class ListConfigsResponse(BaseModel):
|
||||
"""Response schema for listing memory configs.
|
||||
@@ -241,3 +243,149 @@ class ListConfigsResponse(BaseModel):
|
||||
"""
|
||||
configs: List[MemoryConfigItem] = Field(default_factory=list, description="List of configs")
|
||||
total: int = Field(0, description="Total number of configs")
|
||||
|
||||
class ConfigCreateRequest(BaseModel):
|
||||
"""Request schema for creating a new memory config."""
|
||||
config_name: str = Field(..., description="Configuration name")
|
||||
config_desc: Optional[str] = Field("", description="Configuration description")
|
||||
scene_id: uuid.UUID = Field(..., description="Associated ontology scene ID (UUID, required)")
|
||||
|
||||
llm_id: Optional[str] = Field(None, description="LLM model configuration ID")
|
||||
embedding_id: Optional[str] = Field(None, description="Embedding model configuration ID")
|
||||
rerank_id: Optional[str] = Field(None, description="Reranking model configuration ID")
|
||||
reflection_model_id: Optional[str] = Field(None, description="Reflection model ID")
|
||||
emotion_model_id: Optional[str] = Field(None, description="Emotion analysis model ID")
|
||||
|
||||
@field_validator("config_name")
|
||||
@classmethod
|
||||
def validate_config_name(cls, v: str) -> str:
|
||||
if not v or not v.strip():
|
||||
raise ValueError("config_name is required and cannot be empty")
|
||||
return v.strip()
|
||||
|
||||
class ConfigUpdateRequest(BaseModel):
|
||||
"""Request schema for updating memory config basic info.
|
||||
|
||||
Attributes:
|
||||
config_id: Configuration UUID to update (required)
|
||||
config_name: New configuration name
|
||||
config_desc: New configuration description
|
||||
scene_id: New associated ontology scene ID
|
||||
"""
|
||||
config_id: str = Field(..., description="Configuration ID to update")
|
||||
config_name: Optional[str] = Field(None, description="Configuration name")
|
||||
config_desc: Optional[str] = Field(None, description="Configuration description")
|
||||
scene_id: Optional[uuid.UUID] = Field(None, description="Associated ontology scene ID")
|
||||
|
||||
@field_validator("config_id")
|
||||
@classmethod
|
||||
def validate_config_id(cls, v: str) -> str:
|
||||
"""Validate that config_id is not empty."""
|
||||
if not v or not v.strip():
|
||||
raise ValueError("config_id is required and cannot be empty")
|
||||
return v.strip()
|
||||
|
||||
class ConfigUpdateExtractedRequest(BaseModel):
|
||||
"""Request schema for updating memory config extracted parameters.
|
||||
|
||||
Attributes:
|
||||
config_id: Configuration UUID to update (required)
|
||||
llm_id: Optional LLM model configuration ID
|
||||
audio_id: Optional audio model configuration ID
|
||||
vision_id: Optional vision model configuration ID
|
||||
video_id: Optional video model configuration ID
|
||||
embedding_id: Optional embedding model configuration ID
|
||||
rerank_id: Optional reranking model configuration ID
|
||||
enable_llm_dedup_blockwise: Optional toggle for LLM decision deduplication
|
||||
enable_llm_disambiguation: Optional toggle for LLM decision disambiguation
|
||||
deep_retrieval: Optional toggle for deep retrieval
|
||||
|
||||
t_type_strict: Optional float (0-1) for type strictness threshold
|
||||
t_name_strict: Optional float (0-1) for name strictness threshold
|
||||
t_overall: Optional float (0-1) for overall strictness threshold
|
||||
state: Optional boolean for config active state
|
||||
chunker_strategy: Optional string for memory chunking strategy
|
||||
statement_granularity: Optional int (1-3) for statement extraction granularity
|
||||
include_dialogue_context: Optional boolean for including dialogue context in retrieval
|
||||
max_context: Optional int for maximum dialogue context length in characters
|
||||
pruning_enabled: Optional boolean to enable intelligent semantic pruning
|
||||
pruning_scene: Optional string for semantic pruning scene
|
||||
pruning_threshold: Optional float (0-0.9) for semantic pruning threshold
|
||||
enable_self_reflexion: Optional boolean to enable self-reflexion
|
||||
iteration_period: Optional string for reflexion iteration period in hours (1, 3, 6, 12, 24)
|
||||
reflexion_range: Optional string for reflexion range (partial or all)
|
||||
baseline: Optional string for baseline (TIME/FACT/TIME-FACT)
|
||||
|
||||
"""
|
||||
config_id: str = Field(..., description="Configuration ID (UUID)")
|
||||
llm_id: Optional[str] = Field(None, description="LLM model configuration ID")
|
||||
audio_id: Optional[str] = Field(None, description="Audio model ID")
|
||||
vision_id: Optional[str] = Field(None, description="Vision model ID")
|
||||
video_id: Optional[str] = Field(None, description="Video model ID")
|
||||
embedding_id: Optional[str] = Field(None, description="Embedding model configuration ID")
|
||||
rerank_id: Optional[str] = Field(None, description="Reranking model configuration ID")
|
||||
enable_llm_dedup_blockwise: Optional[bool] = Field(None, description="Enable LLM decision deduplication")
|
||||
enable_llm_disambiguation: Optional[bool] = Field(None, description="Enable LLM decision disambiguation")
|
||||
deep_retrieval: Optional[bool] = Field(None, description="Deep retrieval toggle")
|
||||
|
||||
t_type_strict: Optional[float] = Field(None, ge=0.0, le=1.0, description="type strictness threshold")
|
||||
t_name_strict: Optional[float] = Field(None, ge=0.0, le=1.0, description="name strictness threshold")
|
||||
t_overall: Optional[float] = Field(None, ge=0.0, le=1.0, description="overall strictness threshold")
|
||||
state: Optional[bool] = Field(None, description="config active state")
|
||||
# 句子提取
|
||||
chunker_strategy: Optional[str] = Field(None, description="memory chunking strategy")
|
||||
statement_granularity: Optional[int] = Field(None, ge=1, le=3, description="statement extraction granularity")
|
||||
include_dialogue_context: Optional[bool] = Field(None, description="whether to include dialogue context in retrieval")
|
||||
max_context: Optional[int] = Field(None, gt=100, description="maximum dialogue context length in characters")
|
||||
# 剪枝配置:与 runtime.json 中 pruning 段对应
|
||||
pruning_enabled: Optional[bool] = Field(None, description="whether to enable intelligent semantic pruning")
|
||||
pruning_scene: Optional[str] = Field(None, description="semantic pruning scene")
|
||||
pruning_threshold: Optional[float] = Field(None, ge=0.0, le=0.9, description="semantic pruning threshold (0-0.9)")
|
||||
enable_self_reflexion: Optional[bool] = Field(None, description="whether to enable self-reflexion")
|
||||
iteration_period: Optional[Literal["1", "3", "6", "12", "24"]] = Field(None, description="reflexion iteration period in hours (1, 3, 6, 12, 24)")
|
||||
reflexion_range: Optional[Literal["partial", "all"]] = Field(None, description="reflexion range: partial/all")
|
||||
baseline: Optional[Literal["TIME", "FACT", "TIME-FACT"]] = Field(None, description="baseline: TIME/FACT/TIME-FACT")
|
||||
|
||||
@field_validator("config_id")
|
||||
@classmethod
|
||||
def validate_config_id(cls, v: str) -> str:
|
||||
if not v or not v.strip():
|
||||
raise ValueError("config_id is required and cannot be empty")
|
||||
return v.strip()
|
||||
|
||||
class ConfigUpdateForgettingRequest(BaseModel):
|
||||
"""Request schema for updating memory config forgetting parameters.
|
||||
|
||||
Attributes:
|
||||
config_id: Configuration UUID to update (required)
|
||||
decay_constant: Decay constant for forgetting
|
||||
lambda_time: Time decay parameter
|
||||
lambda_mem: Memory decay parameter
|
||||
offset: Offset for forgetting curve
|
||||
max_history_length: Maximum history length to consider for forgetting
|
||||
forgetting_threshold: Threshold for forgetting
|
||||
min_days_since_access: Minimum days since last access to trigger forgetting
|
||||
enable_llm_summary: Whether to use LLM-generated summaries for forgetting
|
||||
max_merge_batch_size: Maximum batch size for merging nodes during forgetting
|
||||
forgetting_interval_hours: Interval in hours for periodic forgetting
|
||||
|
||||
"""
|
||||
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
||||
config_id: str = Field(..., description="Configuration ID (UUID)")
|
||||
decay_constant: Optional[float] = Field(None, ge=0.0, le=1.0, description="Decay constant for forgetting")
|
||||
lambda_time: Optional[float] = Field(None, ge=0.0, le=1.0, description="Time decay parameter")
|
||||
lambda_mem: Optional[float] = Field(None, ge=0.0, le=1.0, description="Memory decay parameter")
|
||||
offset: Optional[float] = Field(None, ge=0.0, le=1.0, description="Offset for forgetting curve")
|
||||
max_history_length: Optional[int] = Field(None, ge=10, le=1000, description="Maximum history length to consider for forgetting")
|
||||
forgetting_threshold: Optional[float] = Field(None, ge=0.0, le=1.0, description="Forgetting threshold")
|
||||
min_days_since_access: Optional[int] = Field(None, ge=1, le=365, description="Minimum days since last access to trigger forgetting")
|
||||
enable_llm_summary: Optional[bool] = Field(None, description="Whether to use LLM-generated summaries for forgetting")
|
||||
max_merge_batch_size: Optional[int] = Field(None, ge=1, le=1000, description="Maximum batch size for merging nodes during forgetting")
|
||||
forgetting_interval_hours: Optional[int] = Field(None, ge=1, le=168, description="Interval in hours for periodic forgetting")
|
||||
|
||||
@field_validator("config_id")
|
||||
@classmethod
|
||||
def validate_config_id(cls, v: str) -> str:
|
||||
if not v or not v.strip():
|
||||
raise ValueError("config_id is required and cannot be empty")
|
||||
return v.strip()
|
||||
Reference in New Issue
Block a user