mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-10 23:59:45 +08:00
- Added detailed explanations and examples for cursor semantics in `api-types.md`, clarifying the exclusive nature of cursors in pagination. - Updated `CursorPaginationParams` interface to emphasize the cursor's role as an exclusive boundary in responses. - Refactored `BranchMessagesQueryParams` to extend `CursorPaginationParams`, aligning with the new pagination logic. - Modified `MessageService` to implement cursor-based pagination semantics, ensuring accurate message retrieval and response structure. - Enhanced documentation throughout to provide clearer guidance on pagination behavior and usage patterns.
214 lines
6.3 KiB
TypeScript
214 lines
6.3 KiB
TypeScript
/**
|
|
* Message API Schema definitions
|
|
*
|
|
* Contains all message-related endpoints for tree operations and message management.
|
|
* Includes endpoints for tree visualization and conversation view.
|
|
*/
|
|
|
|
import type { CursorPaginationParams } from '@shared/data/api/apiTypes'
|
|
import type {
|
|
BranchMessagesResponse,
|
|
Message,
|
|
MessageData,
|
|
MessageRole,
|
|
MessageStats,
|
|
MessageStatus,
|
|
TreeResponse
|
|
} from '@shared/data/types/message'
|
|
import type { AssistantMeta, ModelMeta } from '@shared/data/types/meta'
|
|
|
|
// ============================================================================
|
|
// DTOs
|
|
// ============================================================================
|
|
|
|
/**
|
|
* DTO for creating a new message
|
|
*/
|
|
export interface CreateMessageDto {
|
|
/**
|
|
* Parent message ID for positioning this message in the conversation tree.
|
|
*
|
|
* Behavior:
|
|
* - `undefined` (omitted): Auto-resolve parent based on topic state:
|
|
* - If topic has no messages: create as root (parentId = null)
|
|
* - If topic has messages and activeNodeId is set: attach to activeNodeId
|
|
* - If topic has messages but no activeNodeId: throw INVALID_OPERATION error
|
|
* - `null` (explicit): Create as root message. Throws INVALID_OPERATION if
|
|
* topic already has a root message (only one root allowed per topic).
|
|
* - `string` (message ID): Attach to specified parent. Throws NOT_FOUND if
|
|
* parent doesn't exist, or INVALID_OPERATION if parent belongs to different topic.
|
|
*/
|
|
parentId?: string | null
|
|
/** Message role */
|
|
role: MessageRole
|
|
/** Message content */
|
|
data: MessageData
|
|
/** Message status */
|
|
status?: MessageStatus
|
|
/** Siblings group ID (0 = normal, >0 = multi-model group) */
|
|
siblingsGroupId?: number
|
|
/** Assistant ID */
|
|
assistantId?: string
|
|
/** Preserved assistant info */
|
|
assistantMeta?: AssistantMeta
|
|
/** Model identifier */
|
|
modelId?: string
|
|
/** Preserved model info */
|
|
modelMeta?: ModelMeta
|
|
/** Trace ID */
|
|
traceId?: string
|
|
/** Statistics */
|
|
stats?: MessageStats
|
|
/** Set this message as the active node in the topic (default: true) */
|
|
setAsActive?: boolean
|
|
}
|
|
|
|
/**
|
|
* DTO for updating an existing message
|
|
*/
|
|
export interface UpdateMessageDto {
|
|
/** Updated message content */
|
|
data?: MessageData
|
|
/** Move message to new parent */
|
|
parentId?: string | null
|
|
/** Change siblings group */
|
|
siblingsGroupId?: number
|
|
/** Update status */
|
|
status?: MessageStatus
|
|
/** Update trace ID */
|
|
traceId?: string | null
|
|
/** Update statistics */
|
|
stats?: MessageStats | null
|
|
}
|
|
|
|
/**
|
|
* Strategy for updating activeNodeId when the active message is deleted
|
|
*/
|
|
export type ActiveNodeStrategy = 'parent' | 'clear'
|
|
|
|
/**
|
|
* Response for delete operation
|
|
*/
|
|
export interface DeleteMessageResponse {
|
|
/** IDs of deleted messages */
|
|
deletedIds: string[]
|
|
/** IDs of reparented children (only when cascade=false) */
|
|
reparentedIds?: string[]
|
|
/** New activeNodeId for the topic (only if activeNodeId was affected by deletion) */
|
|
newActiveNodeId?: string | null
|
|
}
|
|
|
|
// ============================================================================
|
|
// Query Parameters
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Query parameters for GET /topics/:id/tree
|
|
*/
|
|
export interface TreeQueryParams {
|
|
/** Root node ID (defaults to tree root) */
|
|
rootId?: string
|
|
/** End node ID (defaults to topic.activeNodeId) */
|
|
nodeId?: string
|
|
/** Depth to expand beyond active path (-1 = all, 0 = path only, 1+ = layers) */
|
|
depth?: number
|
|
}
|
|
|
|
/**
|
|
* Query parameters for GET /topics/:id/messages
|
|
*
|
|
* Uses "before cursor" semantics for loading historical messages:
|
|
* - First request (no cursor): Returns the most recent `limit` messages
|
|
* - Subsequent requests: Pass `nextCursor` from previous response as `cursor`
|
|
* to load older messages towards root
|
|
* - The cursor message itself is NOT included in the response
|
|
*/
|
|
export interface BranchMessagesQueryParams extends CursorPaginationParams {
|
|
/** End node ID (defaults to topic.activeNodeId) */
|
|
nodeId?: string
|
|
/** Whether to include siblingsGroup in response */
|
|
includeSiblings?: boolean
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Schema Definitions
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Message API Schema definitions
|
|
*
|
|
* Organized by domain responsibility:
|
|
* - /topics/:id/tree - Tree visualization
|
|
* - /topics/:id/messages - Branch messages for conversation
|
|
* - /messages/:id - Individual message operations
|
|
*/
|
|
export interface MessageSchemas {
|
|
/**
|
|
* Tree query endpoint for visualization
|
|
* @example GET /topics/abc123/tree?depth=1
|
|
*/
|
|
'/topics/:topicId/tree': {
|
|
/** Get tree structure for visualization */
|
|
GET: {
|
|
params: { topicId: string }
|
|
query?: TreeQueryParams
|
|
response: TreeResponse
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Branch messages endpoint for conversation view
|
|
* @example GET /topics/abc123/messages?limit=20
|
|
* @example POST /topics/abc123/messages { "parentId": "msg1", "role": "user", "data": {...} }
|
|
*/
|
|
'/topics/:topicId/messages': {
|
|
/** Get messages along active branch with pagination */
|
|
GET: {
|
|
params: { topicId: string }
|
|
query?: BranchMessagesQueryParams
|
|
response: BranchMessagesResponse
|
|
}
|
|
/** Create a new message in the topic */
|
|
POST: {
|
|
params: { topicId: string }
|
|
body: CreateMessageDto
|
|
response: Message
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Individual message endpoint
|
|
* @example GET /messages/msg123
|
|
* @example PATCH /messages/msg123 { "data": {...} }
|
|
* @example DELETE /messages/msg123?cascade=true
|
|
*/
|
|
'/messages/:id': {
|
|
/** Get a single message by ID */
|
|
GET: {
|
|
params: { id: string }
|
|
response: Message
|
|
}
|
|
/** Update a message (content, move to new parent, etc.) */
|
|
PATCH: {
|
|
params: { id: string }
|
|
body: UpdateMessageDto
|
|
response: Message
|
|
}
|
|
/**
|
|
* Delete a message
|
|
* - cascade=true: deletes message and all descendants
|
|
* - cascade=false: reparents children to grandparent
|
|
* - activeNodeStrategy='parent' (default): sets activeNodeId to parent if affected
|
|
* - activeNodeStrategy='clear': sets activeNodeId to null if affected
|
|
*/
|
|
DELETE: {
|
|
params: { id: string }
|
|
query?: {
|
|
cascade?: boolean
|
|
activeNodeStrategy?: ActiveNodeStrategy
|
|
}
|
|
response: DeleteMessageResponse
|
|
}
|
|
}
|
|
}
|