Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
77 lines
3 KiB
JavaScript
77 lines
3 KiB
JavaScript
/**
|
|
* Tool Approval Flow routes (Ticket #74075).
|
|
*/
|
|
|
|
import {
|
|
apiLogger,
|
|
success, error, badRequest, notFound,
|
|
approveToolExecution, rejectToolExecution, getPendingApprovals,
|
|
getApprovalRules, updateApprovalRule,
|
|
} from './chatShared.js';
|
|
|
|
export default function registerToolApprovalRoutes(router) {
|
|
|
|
// POST /conversations/:id/tools/:messageId/approve
|
|
router.post('/conversations/:id/tools/:messageId/approve', async (req, res) => {
|
|
try {
|
|
const messageId = parseInt(req.params.messageId);
|
|
const { alwaysAllow } = req.body;
|
|
const result = await approveToolExecution(messageId, req.user.id, !!alwaysAllow);
|
|
return success(res, result);
|
|
} catch (err) {
|
|
apiLogger.error({ error: err.message, messageId: req.params.messageId }, 'Failed to approve tool execution');
|
|
if (err.message.includes('not found') || err.message.includes('not pending')) return badRequest(res, err.message);
|
|
return error(res, 'TOOL_APPROVE_ERROR', err.message, 500);
|
|
}
|
|
});
|
|
|
|
// POST /conversations/:id/tools/:messageId/reject
|
|
router.post('/conversations/:id/tools/:messageId/reject', async (req, res) => {
|
|
try {
|
|
const messageId = parseInt(req.params.messageId);
|
|
const { reason } = req.body;
|
|
const result = await rejectToolExecution(messageId, req.user.id, reason);
|
|
return success(res, result);
|
|
} catch (err) {
|
|
apiLogger.error({ error: err.message, messageId: req.params.messageId }, 'Failed to reject tool execution');
|
|
if (err.message.includes('not found') || err.message.includes('not pending')) return badRequest(res, err.message);
|
|
return error(res, 'TOOL_REJECT_ERROR', err.message, 500);
|
|
}
|
|
});
|
|
|
|
// GET /conversations/:id/pending-approvals
|
|
router.get('/conversations/:id/pending-approvals', async (req, res) => {
|
|
try {
|
|
const conversationId = parseInt(req.params.id);
|
|
const approvals = await getPendingApprovals(conversationId);
|
|
return success(res, approvals);
|
|
} catch (err) {
|
|
apiLogger.error({ error: err.message, conversationId: req.params.id }, 'Failed to get pending approvals');
|
|
return error(res, 'PENDING_APPROVALS_ERROR', err.message, 500);
|
|
}
|
|
});
|
|
|
|
// GET /tool-approval-rules
|
|
router.get('/tool-approval-rules', async (req, res) => {
|
|
try {
|
|
const rules = await getApprovalRules();
|
|
return success(res, rules);
|
|
} catch (err) {
|
|
apiLogger.error({ error: err.message }, 'Failed to get tool approval rules');
|
|
return error(res, 'APPROVAL_RULES_ERROR', err.message, 500);
|
|
}
|
|
});
|
|
|
|
// PUT /tool-approval-rules/:id
|
|
router.put('/tool-approval-rules/:id', async (req, res) => {
|
|
try {
|
|
const ruleId = parseInt(req.params.id);
|
|
const rule = await updateApprovalRule(ruleId, req.body);
|
|
return success(res, rule);
|
|
} catch (err) {
|
|
apiLogger.error({ error: err.message, ruleId: req.params.id }, 'Failed to update tool approval rule');
|
|
if (err.message.includes('not found')) return notFound(res, err.message);
|
|
return error(res, 'UPDATE_RULE_ERROR', err.message, 500);
|
|
}
|
|
});
|
|
}
|