✨ feat: add comprehensive PUT/PATCH support for agents and sessions APIs
- Add PATCH method to agents API for partial updates alongside existing PUT - Add PUT method to sessions API for complete replacement alongside existing PATCH - Update API documentation with clear PUT vs PATCH usage examples - Refactor session status updates to use standard PATCH endpoint - Ensure both methods use same validation middleware for consistency - Add comprehensive Swagger documentation for new endpoints This provides REST-compliant update operations where: - PUT: Complete resource replacement (idempotent) - PATCH: Partial resource updates (only specified fields) Both agents and sessions now support flexible update patterns for different use cases.
This commit is contained in:
@@ -488,6 +488,144 @@ router.put(
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /v1/agents/{agentId}:
|
||||
* patch:
|
||||
* summary: Partially update agent
|
||||
* description: Partially updates an existing agent with only the provided fields
|
||||
* tags: [Agents]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: agentId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Agent ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description: Agent name
|
||||
* description:
|
||||
* type: string
|
||||
* description: Agent description
|
||||
* avatar:
|
||||
* type: string
|
||||
* description: Agent avatar URL
|
||||
* instructions:
|
||||
* type: string
|
||||
* description: System prompt/instructions
|
||||
* model:
|
||||
* type: string
|
||||
* description: Main model ID
|
||||
* plan_model:
|
||||
* type: string
|
||||
* description: Optional planning model ID
|
||||
* small_model:
|
||||
* type: string
|
||||
* description: Optional small/fast model ID
|
||||
* built_in_tools:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* description: Built-in tool IDs
|
||||
* mcps:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* description: MCP tool IDs
|
||||
* knowledges:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* description: Knowledge base IDs
|
||||
* configuration:
|
||||
* type: object
|
||||
* description: Extensible settings
|
||||
* accessible_paths:
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* description: Accessible directory paths
|
||||
* permission_mode:
|
||||
* type: string
|
||||
* enum: [readOnly, acceptEdits, bypassPermissions]
|
||||
* description: Permission mode
|
||||
* max_steps:
|
||||
* type: integer
|
||||
* description: Maximum steps the agent can take
|
||||
* description: Only include the fields you want to update
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Agent updated successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AgentEntity'
|
||||
* 400:
|
||||
* description: Validation error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Agent not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 500:
|
||||
* description: Internal server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
router.patch(
|
||||
'/:agentId',
|
||||
validateAgentId,
|
||||
validateAgentUpdate,
|
||||
handleValidationErrors,
|
||||
async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { agentId } = req.params
|
||||
logger.info(`Partially updating agent: ${agentId}`)
|
||||
logger.debug('Partial update data:', req.body)
|
||||
|
||||
const agent = await agentService.updateAgent(agentId, req.body)
|
||||
|
||||
if (!agent) {
|
||||
logger.warn(`Agent not found for partial update: ${agentId}`)
|
||||
return res.status(404).json({
|
||||
error: {
|
||||
message: 'Agent not found',
|
||||
type: 'not_found',
|
||||
code: 'agent_not_found'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
logger.info(`Agent partially updated successfully: ${agentId}`)
|
||||
return res.json(agent)
|
||||
} catch (error: any) {
|
||||
logger.error('Error partially updating agent:', error)
|
||||
return res.status(500).json({
|
||||
error: {
|
||||
message: 'Failed to partially update agent',
|
||||
type: 'internal_error',
|
||||
code: 'agent_patch_failed'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /v1/agents/{agentId}:
|
||||
|
||||
@@ -11,7 +11,6 @@ const router = express.Router()
|
||||
// Validation middleware
|
||||
const validateSession = [
|
||||
body('name').optional().isString(),
|
||||
body('main_agent_id').notEmpty().withMessage('Main agent ID is required'),
|
||||
body('sub_agent_ids').optional().isArray(),
|
||||
body('user_goal').optional().isString(),
|
||||
body('status').optional().isIn(['idle', 'running', 'completed', 'failed', 'stopped']),
|
||||
@@ -545,6 +544,114 @@ function createSessionsRouter(): express.Router {
|
||||
* @swagger
|
||||
* /v1/agents/{agentId}/sessions/{sessionId}:
|
||||
* put:
|
||||
* summary: Replace session
|
||||
* description: Completely replaces an existing session for the specified agent
|
||||
* tags: [Sessions]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: agentId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Agent ID
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Session ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/CreateSessionRequest'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Session replaced successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AgentSessionEntity'
|
||||
* 400:
|
||||
* description: Validation error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Agent or session not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 500:
|
||||
* description: Internal server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
sessionsRouter.put(
|
||||
'/:sessionId',
|
||||
validateAgentId,
|
||||
validateSessionId,
|
||||
checkAgentExists,
|
||||
validateSessionUpdate,
|
||||
handleValidationErrors,
|
||||
async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { agentId, sessionId } = req.params
|
||||
logger.info(`Replacing session: ${sessionId} for agent: ${agentId}`)
|
||||
logger.debug('Replace data:', req.body)
|
||||
|
||||
// First check if session exists and belongs to agent
|
||||
const existingSession = await sessionService.getSession(sessionId)
|
||||
if (!existingSession || existingSession.main_agent_id !== agentId) {
|
||||
logger.warn(`Session ${sessionId} not found for agent ${agentId}`)
|
||||
return res.status(404).json({
|
||||
error: {
|
||||
message: 'Session not found for this agent',
|
||||
type: 'not_found',
|
||||
code: 'session_not_found'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// For PUT, we replace the entire resource
|
||||
const sessionData = { ...req.body, main_agent_id: agentId }
|
||||
const session = await sessionService.updateSession(sessionId, sessionData)
|
||||
|
||||
if (!session) {
|
||||
logger.warn(`Session not found for replace: ${sessionId}`)
|
||||
return res.status(404).json({
|
||||
error: {
|
||||
message: 'Session not found',
|
||||
type: 'not_found',
|
||||
code: 'session_not_found'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
logger.info(`Session replaced successfully: ${sessionId}`)
|
||||
return res.json(session)
|
||||
} catch (error: any) {
|
||||
logger.error('Error replacing session:', error)
|
||||
return res.status(500).json({
|
||||
error: {
|
||||
message: 'Failed to replace session',
|
||||
type: 'internal_error',
|
||||
code: 'session_replace_failed'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /v1/agents/{agentId}/sessions/{sessionId}:
|
||||
* patch:
|
||||
* summary: Update session
|
||||
* description: Updates an existing session for the specified agent
|
||||
* tags: [Sessions]
|
||||
@@ -593,7 +700,7 @@ function createSessionsRouter(): express.Router {
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
sessionsRouter.put(
|
||||
sessionsRouter.patch(
|
||||
'/:sessionId',
|
||||
validateAgentId,
|
||||
validateSessionId,
|
||||
@@ -618,8 +725,8 @@ function createSessionsRouter(): express.Router {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const session = await sessionService.updateSession(sessionId, req.body)
|
||||
const updateSession = { ...existingSession, ...req.body }
|
||||
const session = await sessionService.updateSession(sessionId, updateSession)
|
||||
|
||||
if (!session) {
|
||||
logger.warn(`Session not found for update: ${sessionId}`)
|
||||
@@ -647,119 +754,6 @@ function createSessionsRouter(): express.Router {
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /v1/agents/{agentId}/sessions/{sessionId}/status:
|
||||
* patch:
|
||||
* summary: Update session status
|
||||
* description: Updates the status of a specific session
|
||||
* tags: [Sessions]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: agentId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Agent ID
|
||||
* - in: path
|
||||
* name: sessionId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Session ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* enum: [idle, running, completed, failed, stopped]
|
||||
* required:
|
||||
* - status
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Session status updated successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/AgentSessionEntity'
|
||||
* 400:
|
||||
* description: Validation error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Agent or session not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 500:
|
||||
* description: Internal server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
sessionsRouter.patch(
|
||||
'/:sessionId/status',
|
||||
validateAgentId,
|
||||
validateSessionId,
|
||||
checkAgentExists,
|
||||
validateStatusUpdate,
|
||||
handleValidationErrors,
|
||||
async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { agentId, sessionId } = req.params
|
||||
const { status } = req.body
|
||||
|
||||
logger.info(`Updating session status: ${sessionId} for agent: ${agentId} to ${status}`)
|
||||
|
||||
// First check if session exists and belongs to agent
|
||||
const existingSession = await sessionService.getSession(sessionId)
|
||||
if (!existingSession || existingSession.main_agent_id !== agentId) {
|
||||
logger.warn(`Session ${sessionId} not found for agent ${agentId}`)
|
||||
return res.status(404).json({
|
||||
error: {
|
||||
message: 'Session not found for this agent',
|
||||
type: 'not_found',
|
||||
code: 'session_not_found'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const session = await sessionService.updateSessionStatus(sessionId, status)
|
||||
|
||||
if (!session) {
|
||||
logger.warn(`Session not found for status update: ${sessionId}`)
|
||||
return res.status(404).json({
|
||||
error: {
|
||||
message: 'Session not found',
|
||||
type: 'not_found',
|
||||
code: 'session_not_found'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
logger.info(`Session status updated successfully: ${sessionId} -> ${status}`)
|
||||
return res.json(session)
|
||||
} catch (error: any) {
|
||||
logger.error('Error updating session status:', error)
|
||||
return res.status(500).json({
|
||||
error: {
|
||||
message: 'Failed to update session status',
|
||||
type: 'internal_error',
|
||||
code: 'session_status_update_failed'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /v1/agents/{agentId}/sessions/{sessionId}:
|
||||
|
||||
Reference in New Issue
Block a user