|
1 | 1 | import os |
2 | 2 | import uuid |
3 | 3 |
|
4 | | -from typing import Generic, Literal, TypeVar |
| 4 | +from typing import Any, Generic, Literal, TypeVar |
5 | 5 |
|
6 | 6 | from pydantic import BaseModel, Field |
7 | 7 |
|
@@ -175,25 +175,117 @@ class SearchRequest(BaseRequest): |
175 | 175 | class APISearchRequest(BaseRequest): |
176 | 176 | """Request model for searching memories.""" |
177 | 177 |
|
178 | | - query: str = Field(..., description="Search query") |
179 | | - user_id: str = Field(None, description="User ID") |
180 | | - mem_cube_id: str | None = Field(None, description="Cube ID to search in") |
| 178 | + # ==== Basic inputs ==== |
| 179 | + query: str = Field( |
| 180 | + ..., |
| 181 | + description=("User search query"), |
| 182 | + ) |
| 183 | + user_id: str = Field(..., description="User ID") |
| 184 | + |
| 185 | + # ==== Cube scoping ==== |
| 186 | + mem_cube_id: str | None = Field( |
| 187 | + None, |
| 188 | + description=( |
| 189 | + "(Deprecated) Single cube ID to search in. " |
| 190 | + "Prefer `readable_cube_ids` for multi-cube search." |
| 191 | + ), |
| 192 | + ) |
181 | 193 | readable_cube_ids: list[str] | None = Field( |
182 | | - None, description="List of cube IDs user can read for multi-cube search" |
| 194 | + None, |
| 195 | + description=( |
| 196 | + "List of cube IDs that are readable for this request. " |
| 197 | + "Required for algorithm-facing API; optional for developer-facing API." |
| 198 | + ), |
183 | 199 | ) |
| 200 | + |
| 201 | + # ==== Search mode ==== |
184 | 202 | mode: SearchMode = Field( |
185 | | - os.getenv("SEARCH_MODE", SearchMode.FAST), description="search mode: fast, fine, or mixture" |
| 203 | + os.getenv("SEARCH_MODE", SearchMode.FAST), |
| 204 | + description="Search mode: FAST, FINE, or MIXTURE.", |
186 | 205 | ) |
187 | | - internet_search: bool = Field(False, description="Whether to use internet search") |
188 | | - moscube: bool = Field(False, description="Whether to use MemOSCube") |
189 | | - top_k: int = Field(10, description="Number of results to return") |
190 | | - chat_history: list[MessageDict] | None = Field(None, description="Chat history") |
191 | | - session_id: str | None = Field(None, description="Session ID for soft-filtering memories") |
| 206 | + |
| 207 | + session_id: str | None = Field( |
| 208 | + None, |
| 209 | + description=( |
| 210 | + "Session ID used as a soft signal to prioritize more relevant memories. " |
| 211 | + "Only used for weighting, not as a hard filter." |
| 212 | + ), |
| 213 | + ) |
| 214 | + |
| 215 | + # ==== Result control ==== |
| 216 | + top_k: int = Field( |
| 217 | + 10, |
| 218 | + ge=1, |
| 219 | + description="Number of textual memories to retrieve (top-K). Default: 10.", |
| 220 | + ) |
| 221 | + |
| 222 | + pref_top_k: int = Field( |
| 223 | + 6, |
| 224 | + ge=0, |
| 225 | + description="Number of preference memories to retrieve (top-K). Default: 6.", |
| 226 | + ) |
| 227 | + |
| 228 | + include_preference: bool = Field( |
| 229 | + True, |
| 230 | + description=( |
| 231 | + "Whether to retrieve preference memories along with general memories. " |
| 232 | + "If enabled, the system will automatically recall user preferences " |
| 233 | + "relevant to the query. Default: True." |
| 234 | + ), |
| 235 | + ) |
| 236 | + |
| 237 | + # ==== Filter conditions ==== |
| 238 | + filter: dict[str, Any] | None = Field( |
| 239 | + None, |
| 240 | + description=( |
| 241 | + "Structured filter conditions for searching memories. " |
| 242 | + "Supports logical operators: AND, OR, NOT; " |
| 243 | + "comparison: E (==), NE (!=), GT (>), LT (<), GTE (>=), LTE (<=); " |
| 244 | + "arithmetic: +, -, *, /, %, **; " |
| 245 | + "set: IN, CONTAINS, ICONTAINS; " |
| 246 | + "string: LIKE. " |
| 247 | + "This nested dict will be converted into an internal expression tree." |
| 248 | + ), |
| 249 | + ) |
| 250 | + |
| 251 | + # ==== Extended capabilities ==== |
| 252 | + internet_search: bool = Field( |
| 253 | + False, |
| 254 | + description=( |
| 255 | + "Whether to enable internet search in addition to memory search. " |
| 256 | + "Primarily used by internal algorithms. Default: False." |
| 257 | + ), |
| 258 | + ) |
| 259 | + |
| 260 | + # Inner user, not supported in API yet |
| 261 | + threshold: float | None = Field( |
| 262 | + None, |
| 263 | + description=( |
| 264 | + "Internal similarity threshold for searching plaintext memories. " |
| 265 | + "If None, default thresholds will be applied." |
| 266 | + ), |
| 267 | + ) |
| 268 | + |
| 269 | + # ==== Context ==== |
| 270 | + chat_history: list[MessageDict] | None = Field( |
| 271 | + None, |
| 272 | + description=( |
| 273 | + "Historical chat messages used internally by algorithms. " |
| 274 | + "If None, internal stored history may be used; " |
| 275 | + "if provided (even an empty list), this value will be used as-is." |
| 276 | + ), |
| 277 | + ) |
| 278 | + |
| 279 | + # ==== Backward compatibility ==== |
| 280 | + moscube: bool = Field( |
| 281 | + False, |
| 282 | + description="(Deprecated / internal) Whether to use legacy MemOSCube path.", |
| 283 | + ) |
| 284 | + |
192 | 285 | operation: list[PermissionDict] | None = Field( |
193 | | - None, description="operation ids for multi cubes" |
| 286 | + None, |
| 287 | + description="(Internal) Operation definitions for multi-cube read permissions.", |
194 | 288 | ) |
195 | | - include_preference: bool = Field(True, description="Whether to handle preference memory") |
196 | | - pref_top_k: int = Field(6, description="Number of preference results to return") |
197 | 289 |
|
198 | 290 |
|
199 | 291 | class APIADDRequest(BaseRequest): |
|
0 commit comments