🔧 fix: Agent Versioning with Action Hashing and OAuth Redirect (#7627)

* 🔧 chore: Update navigateFallbackDenylist in Vite config to include API routes

* 🔧 fix: Update redirect_uri in createActionTool to use DOMAIN_SERVER instead of DOMAIN_CLIENT

* 🔧 feat: Enhance Agent Versioning with Action Metadata Hashing

- Added support for generating a hash of action metadata to detect changes and manage agent versioning.
- Updated `updateAgent` function to include an optional `forceVersion` parameter for version creation.
- Modified `isDuplicateVersion` to compare action metadata hashes.
- Updated related tests to validate new versioning behavior with action changes.
- Refactored agent update logic to ensure proper tracking of user updates and version history.
This commit is contained in:
Danny Avila 2025-05-29 10:30:35 -04:00 committed by GitHub
parent fb88ac00c6
commit 442976c74f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 213 additions and 31 deletions

View file

@ -111,7 +111,7 @@ const getAgentHandler = async (req, res) => {
const originalUrl = agent.avatar.filepath;
agent.avatar.filepath = await refreshS3Url(agent.avatar);
if (originalUrl !== agent.avatar.filepath) {
await updateAgent({ id }, { avatar: agent.avatar }, req.user.id);
await updateAgent({ id }, { avatar: agent.avatar }, { updatingUserId: req.user.id });
}
}
@ -170,7 +170,7 @@ const updateAgentHandler = async (req, res) => {
let updatedAgent =
Object.keys(updateData).length > 0
? await updateAgent({ id }, updateData, req.user.id)
? await updateAgent({ id }, updateData, { updatingUserId: req.user.id })
: existingAgent;
if (projectIds || removeProjectIds) {
@ -407,7 +407,11 @@ const uploadAgentAvatarHandler = async (req, res) => {
},
};
promises.push(await updateAgent({ id: agent_id, author: req.user.id }, data, req.user.id));
promises.push(
await updateAgent({ id: agent_id, author: req.user.id }, data, {
updatingUserId: req.user.id,
}),
);
const resolved = await Promise.all(promises);
res.status(201).json(resolved[0]);

View file

@ -107,7 +107,15 @@ router.post('/:agent_id', async (req, res) => {
.filter((tool) => !(tool && (tool.includes(domain) || tool.includes(action_id))))
.concat(functions.map((tool) => `${tool.function.name}${actionDelimiter}${domain}`));
const updatedAgent = await updateAgent(agentQuery, { tools, actions }, req.user.id);
// Force version update since actions are changing
const updatedAgent = await updateAgent(
agentQuery,
{ tools, actions },
{
updatingUserId: req.user.id,
forceVersion: true,
},
);
// Only update user field for new actions
const actionUpdateData = { metadata, agent_id };
@ -172,7 +180,12 @@ router.delete('/:agent_id/:action_id', async (req, res) => {
const updatedTools = tools.filter((tool) => !(tool && tool.includes(domain)));
await updateAgent(agentQuery, { tools: updatedTools, actions: updatedActions }, req.user.id);
// Force version update since actions are being removed
await updateAgent(
agentQuery,
{ tools: updatedTools, actions: updatedActions },
{ updatingUserId: req.user.id, forceVersion: true },
);
// If admin, can delete any action, otherwise only user's actions
const actionQuery = admin ? { action_id } : { action_id, user: req.user.id };
await deleteAction(actionQuery);

View file

@ -207,7 +207,7 @@ async function createActionTool({
state: stateToken,
userId: userId,
client_url: metadata.auth.client_url,
redirect_uri: `${process.env.DOMAIN_CLIENT}/api/actions/${action_id}/oauth/callback`,
redirect_uri: `${process.env.DOMAIN_SERVER}/api/actions/${action_id}/oauth/callback`,
/** Encrypted values */
encrypted_oauth_client_id: encrypted.oauth_client_id,
encrypted_oauth_client_secret: encrypted.oauth_client_secret,