mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 20:12:38 +08:00
✨ feat: implement comprehensive CRUD APIs for agent management with type support
This commit is contained in:
parent
e3f5033bc4
commit
5eaa90a7a2
224
plan.md
Normal file
224
plan.md
Normal file
@ -0,0 +1,224 @@
|
||||
Overview
|
||||
|
||||
Implement comprehensive CRUD APIs for agent, agentSession, and agentSessionLogs management
|
||||
in Cherry Studio's API server using RESTful URL conventions.
|
||||
|
||||
Architecture Overview
|
||||
|
||||
1. Service Layer
|
||||
|
||||
- Create AgentService class in src/main/services/agents/AgentService.ts
|
||||
- Handles database operations using SQL queries from db.ts
|
||||
- Manages SQLite database initialization and connections
|
||||
- Provides business logic for agent operations
|
||||
|
||||
2. API Routes
|
||||
|
||||
- Create route files in src/main/apiServer/routes/:
|
||||
- agents.ts - Agent CRUD endpoints
|
||||
- sessions.ts - Session CRUD endpoints
|
||||
- session-logs.ts - Session logs CRUD endpoints
|
||||
|
||||
3. Database Integration
|
||||
|
||||
- Use SQLite with @libsql/client (following MemoryService pattern)
|
||||
- Database location: userData/agents.db
|
||||
- Leverage existing SQL queries in src/main/services/agents/db.ts
|
||||
|
||||
Implementation Steps
|
||||
|
||||
Phase 1: Database Service Setup
|
||||
|
||||
1. Create AgentService class with database initialization
|
||||
2. Implement database connection management
|
||||
3. Add database initialization to main process startup
|
||||
4. Create helper methods for JSON field serialization/deserialization
|
||||
|
||||
Phase 2: Agent CRUD Operations
|
||||
|
||||
1. Implement service methods:
|
||||
- createAgent(agent: Omit<AgentEntity, 'id' | 'created_at' | 'updated_at'>)
|
||||
- getAgent(id: string)
|
||||
- listAgents(options?: { limit?: number, offset?: number })
|
||||
- updateAgent(id: string, updates: Partial<AgentEntity>)
|
||||
- deleteAgent(id: string)
|
||||
2. Create API routes:
|
||||
- POST /v1/agents - Create agent
|
||||
- GET /v1/agents - List all agents
|
||||
- GET /v1/agents/:agentId - Get agent by ID
|
||||
- PUT /v1/agents/:agentId - Update agent
|
||||
- DELETE /v1/agents/:agentId - Delete agent
|
||||
|
||||
Phase 3: Session CRUD Operations
|
||||
|
||||
1. Implement service methods:
|
||||
- createSession(session: Omit<AgentSessionEntity, 'id' | 'created_at' | 'updated_at'>)
|
||||
- getSession(id: string)
|
||||
- listSessions(agentId?: string, options?: { status?: SessionStatus, limit?: number,
|
||||
offset?: number })
|
||||
- updateSession(id: string, updates: Partial<AgentSessionEntity>)
|
||||
- updateSessionStatus(id: string, status: SessionStatus)
|
||||
- deleteSession(id: string)
|
||||
- getSessionWithAgent(id: string) - Get session with merged agent configuration
|
||||
2. Create API routes (RESTful nested resources):
|
||||
- POST /v1/agents/:agentId/sessions - Create session for specific agent
|
||||
- GET /v1/agents/:agentId/sessions - List sessions for specific agent
|
||||
- GET /v1/agents/:agentId/sessions/:sessionId - Get specific session
|
||||
- PUT /v1/agents/:agentId/sessions/:sessionId - Update session
|
||||
- PATCH /v1/agents/:agentId/sessions/:sessionId/status - Update session status
|
||||
- DELETE /v1/agents/:agentId/sessions/:sessionId - Delete session
|
||||
|
||||
Additional convenience endpoints:
|
||||
- GET /v1/sessions - List all sessions (across all agents)
|
||||
- GET /v1/sessions/:sessionId - Get session by ID (without agent context)
|
||||
|
||||
Phase 4: Session Logs CRUD Operations
|
||||
|
||||
1. Implement service methods:
|
||||
- createSessionLog(log: Omit<SessionLogEntity, 'id' | 'created_at' | 'updated_at'>)
|
||||
- getSessionLog(id: number)
|
||||
- listSessionLogs(sessionId: string, options?: { limit?: number, offset?: number })
|
||||
- updateSessionLog(id: number, updates: { content?: any, metadata?: any })
|
||||
- deleteSessionLog(id: number)
|
||||
- getSessionLogTree(sessionId: string) - Get logs with parent-child relationships
|
||||
- bulkCreateSessionLogs(logs: Array<...>) - Batch insert logs
|
||||
2. Create API routes (RESTful nested resources):
|
||||
- POST /v1/agents/:agentId/sessions/:sessionId/logs - Create log entry
|
||||
- GET /v1/agents/:agentId/sessions/:sessionId/logs - List logs for session
|
||||
- GET /v1/agents/:agentId/sessions/:sessionId/logs/:logId - Get specific log
|
||||
- PUT /v1/agents/:agentId/sessions/:sessionId/logs/:logId - Update log
|
||||
- DELETE /v1/agents/:agentId/sessions/:sessionId/logs/:logId - Delete log
|
||||
- POST /v1/agents/:agentId/sessions/:sessionId/logs/bulk - Bulk create logs
|
||||
|
||||
Additional convenience endpoints:
|
||||
- GET /v1/sessions/:sessionId/logs - Get logs without agent context
|
||||
- GET /v1/session-logs/:logId - Get specific log by ID
|
||||
|
||||
Phase 5: Route Organization
|
||||
|
||||
1. Mount routes with proper nesting:
|
||||
// In app.ts
|
||||
apiRouter.use('/agents', agentsRoutes)
|
||||
// agentsRoutes will handle:
|
||||
// - /agents/*
|
||||
// - /agents/:agentId/sessions/*
|
||||
// - /agents/:agentId/sessions/:sessionId/logs/*
|
||||
|
||||
// Convenience routes
|
||||
apiRouter.use('/sessions', sessionsRoutes)
|
||||
apiRouter.use('/session-logs', sessionLogsRoutes)
|
||||
|
||||
2. Use Express Router mergeParams for nested routes:
|
||||
// In agents.ts
|
||||
const sessionsRouter = express.Router({ mergeParams: true })
|
||||
router.use('/:agentId/sessions', sessionsRouter)
|
||||
|
||||
Phase 6: OpenAPI Documentation
|
||||
|
||||
1. Add Swagger schemas for new entities:
|
||||
- AgentEntity schema
|
||||
- AgentSessionEntity schema
|
||||
- SessionLogEntity schema
|
||||
- Request/Response schemas
|
||||
2. Document all new endpoints with:
|
||||
- Clear path parameters (agentId, sessionId, logId)
|
||||
- Request body schemas
|
||||
- Response examples
|
||||
- Error responses
|
||||
- Proper grouping by resource
|
||||
|
||||
Phase 7: Validation & Error Handling
|
||||
|
||||
1. Add path parameter validation:
|
||||
- Validate agentId exists before processing session requests
|
||||
- Validate sessionId belongs to agentId
|
||||
- Validate logId belongs to sessionId
|
||||
2. Implement middleware for:
|
||||
- Request validation using express-validator
|
||||
- Resource existence checks
|
||||
- Permission validation (future consideration)
|
||||
- Transaction support for complex operations
|
||||
|
||||
Phase 8: Testing
|
||||
|
||||
1. Unit tests for service methods
|
||||
2. Integration tests for API endpoints
|
||||
3. Test nested resource validation
|
||||
4. Test cascading deletes
|
||||
5. Test transaction rollbacks
|
||||
|
||||
File Structure
|
||||
|
||||
src/
|
||||
├── main/
|
||||
│ └── services/
|
||||
│ └── agents/
|
||||
│ ├── index.ts (existing)
|
||||
│ ├── db.ts (existing)
|
||||
│ └── AgentService.ts (new)
|
||||
├── main/
|
||||
│ └── apiServer/
|
||||
│ └── routes/
|
||||
│ ├── agents.ts (new - includes nested routes)
|
||||
│ ├── sessions.ts (new - convenience endpoints)
|
||||
│ └── session-logs.ts (new - convenience endpoints)
|
||||
└── renderer/
|
||||
└── src/
|
||||
└── types/
|
||||
└── agent.ts (existing)
|
||||
|
||||
API Endpoint Summary
|
||||
|
||||
Agent Endpoints
|
||||
|
||||
- POST /v1/agents
|
||||
- GET /v1/agents
|
||||
- GET /v1/agents/:agentId
|
||||
- PUT /v1/agents/:agentId
|
||||
- DELETE /v1/agents/:agentId
|
||||
|
||||
Session Endpoints (RESTful)
|
||||
|
||||
- POST /v1/agents/:agentId/sessions
|
||||
- GET /v1/agents/:agentId/sessions
|
||||
- GET /v1/agents/:agentId/sessions/:sessionId
|
||||
- PUT /v1/agents/:agentId/sessions/:sessionId
|
||||
- PATCH /v1/agents/:agentId/sessions/:sessionId/status
|
||||
- DELETE /v1/agents/:agentId/sessions/:sessionId
|
||||
|
||||
Session Convenience Endpoints
|
||||
|
||||
- GET /v1/sessions
|
||||
- GET /v1/sessions/:sessionId
|
||||
|
||||
Session Log Endpoints (RESTful)
|
||||
|
||||
- POST /v1/agents/:agentId/sessions/:sessionId/logs
|
||||
- GET /v1/agents/:agentId/sessions/:sessionId/logs
|
||||
- GET /v1/agents/:agentId/sessions/:sessionId/logs/:logId
|
||||
- PUT /v1/agents/:agentId/sessions/:sessionId/logs/:logId
|
||||
- DELETE /v1/agents/:agentId/sessions/:sessionId/logs/:logId
|
||||
- POST /v1/agents/:agentId/sessions/:sessionId/logs/bulk
|
||||
|
||||
Session Log Convenience Endpoints
|
||||
|
||||
- GET /v1/sessions/:sessionId/logs
|
||||
- GET /v1/session-logs/:logId
|
||||
|
||||
Key Considerations
|
||||
|
||||
- Follow RESTful URL conventions with proper resource nesting
|
||||
- Validate parent-child relationships in nested routes
|
||||
- Use Express Router with mergeParams for nested routing
|
||||
- Implement proper cascading deletes
|
||||
- Add transaction support for data consistency
|
||||
- Follow existing patterns from MemoryService
|
||||
- Ensure backward compatibility
|
||||
- Add rate limiting for write operations
|
||||
|
||||
Dependencies
|
||||
|
||||
- @libsql/client - SQLite database client
|
||||
- express-validator - Request validation
|
||||
- swagger-jsdoc - API documentation
|
||||
- Existing types from @types/agent.ts
|
||||
@ -1,6 +1,13 @@
|
||||
import { Client, createClient } from '@libsql/client'
|
||||
import { loggerService } from '@logger'
|
||||
import type { AgentEntity, AgentSessionEntity, PermissionMode, SessionLogEntity, SessionStatus } from '@types'
|
||||
import type {
|
||||
AgentEntity,
|
||||
AgentSessionEntity,
|
||||
AgentType,
|
||||
PermissionMode,
|
||||
SessionLogEntity,
|
||||
SessionStatus
|
||||
} from '@types'
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
|
||||
@ -9,6 +16,7 @@ import { AgentQueries } from './db'
|
||||
const logger = loggerService.withContext('AgentService')
|
||||
|
||||
export interface CreateAgentRequest {
|
||||
type: AgentType
|
||||
name: string
|
||||
description?: string
|
||||
avatar?: string
|
||||
@ -201,6 +209,7 @@ export class AgentService {
|
||||
|
||||
const values = [
|
||||
id,
|
||||
serializedData.type,
|
||||
serializedData.name,
|
||||
serializedData.description || null,
|
||||
serializedData.avatar || null,
|
||||
|
||||
@ -8,6 +8,7 @@ export const AgentQueries = {
|
||||
agents: `
|
||||
CREATE TABLE IF NOT EXISTS agents (
|
||||
id TEXT PRIMARY KEY,
|
||||
type TEXT NOT NULL DEFAULT 'custom', -- 'claudeCode', 'codex', 'custom'
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
avatar TEXT,
|
||||
@ -72,6 +73,7 @@ export const AgentQueries = {
|
||||
// Index creation queries
|
||||
createIndexes: {
|
||||
agentsName: 'CREATE INDEX IF NOT EXISTS idx_agents_name ON agents(name)',
|
||||
agentsType: 'CREATE INDEX IF NOT EXISTS idx_agents_type ON agents(type)',
|
||||
agentsModel: 'CREATE INDEX IF NOT EXISTS idx_agents_model ON agents(model)',
|
||||
agentsPlanModel: 'CREATE INDEX IF NOT EXISTS idx_agents_plan_model ON agents(plan_model)',
|
||||
agentsSmallModel: 'CREATE INDEX IF NOT EXISTS idx_agents_small_model ON agents(small_model)',
|
||||
@ -99,8 +101,8 @@ export const AgentQueries = {
|
||||
// Agent operations
|
||||
agents: {
|
||||
insert: `
|
||||
INSERT INTO agents (id, name, description, avatar, instructions, model, plan_model, small_model, built_in_tools, mcps, knowledges, configuration, accessible_paths, permission_mode, max_steps, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO agents (id, type, name, description, avatar, instructions, model, plan_model, small_model, built_in_tools, mcps, knowledges, configuration, accessible_paths, permission_mode, max_steps, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
|
||||
update: `
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
export type SessionStatus = 'idle' | 'running' | 'completed' | 'failed' | 'stopped'
|
||||
export type PermissionMode = 'readOnly' | 'acceptEdits' | 'bypassPermissions'
|
||||
export type SessionLogRole = 'user' | 'agent' | 'system' | 'tool'
|
||||
export type AgentType = 'claude-code' | 'codex' | 'qwen-cli' | 'gemini-cli' | 'custom'
|
||||
|
||||
export type SessionLogType =
|
||||
| 'message' // User or agent message
|
||||
@ -38,6 +39,7 @@ export interface AgentConfiguration {
|
||||
// Agent entity representing an autonomous agent configuration
|
||||
export interface AgentEntity extends AgentConfiguration {
|
||||
id: string
|
||||
type: AgentType
|
||||
name: string
|
||||
description?: string
|
||||
avatar?: string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user