Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions builder/store/database/agent_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func (s *agentTemplateStoreImpl) FindByTypeAndName(ctx context.Context, agentTyp
return templates, nil
}

func (s *agentTemplateStoreImpl) applyAgentTemplateFilters(query *bun.SelectQuery, filter types.AgentTemplateFilter) *bun.SelectQuery {
func (s *agentTemplateStoreImpl) applyAgentTemplateFilters(query *bun.SelectQuery, userUUID string, filter types.AgentTemplateFilter) *bun.SelectQuery {
filter.Search = strings.TrimSpace(filter.Search)
if filter.Search != "" {
searchPattern := "%" + filter.Search + "%"
Expand All @@ -154,6 +154,14 @@ func (s *agentTemplateStoreImpl) applyAgentTemplateFilters(query *bun.SelectQuer
query = query.Where("at.type = ?", filter.Type)
}

if filter.Editable != nil {
if *filter.Editable {
query = query.Where("at.user_uuid = ?", userUUID)
} else {
query = query.Where("at.user_uuid != ?", userUUID)
}
}

return query
}

Expand All @@ -177,7 +185,7 @@ func (s *agentTemplateStoreImpl) ListByUserUUID(ctx context.Context, userUUID st
Where("at.deleted_at IS NULL").
Where("at.user_uuid = ? OR at.public = ?", userUUID, true)

query = s.applyAgentTemplateFilters(query, filter)
query = s.applyAgentTemplateFilters(query, userUUID, filter)

total, err := query.Count(ctx)
if err != nil {
Expand Down
94 changes: 94 additions & 0 deletions builder/store/database/agent_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,97 @@ func TestAgentTemplateStore_ListByUserUUID_WithFilters(t *testing.T) {
require.Len(t, templates, 1) // Should return 1 template on second page
require.Equal(t, 3, total) // Total should still be 3
}

func TestAgentTemplateStore_ListByUserUUID_WithEditableFilter(t *testing.T) {
db := tests.InitTestDB()
defer db.Close()
ctx := context.TODO()

store := database.NewAgentTemplateStoreWithDB(db)

userUUID1 := uuid.New().String()
userUUID2 := uuid.New().String()

// Create user1's private template (owned by user1)
user1Private := &database.AgentTemplate{
Type: "langflow",
UserUUID: userUUID1,
Name: "User1 Private Template",
Content: "private",
Public: false,
}
_, err := store.Create(ctx, user1Private)
require.NoError(t, err)

// Create user1's public template (owned by user1)
user1Public := &database.AgentTemplate{
Type: "code",
UserUUID: userUUID1,
Name: "User1 Public Template",
Content: "public",
Public: true,
}
_, err = store.Create(ctx, user1Public)
require.NoError(t, err)

// Create user2's public template (not owned by user1)
user2Public := &database.AgentTemplate{
Type: "agno",
UserUUID: userUUID2,
Name: "User2 Public Template",
Content: "public",
Public: true,
}
_, err = store.Create(ctx, user2Public)
require.NoError(t, err)

// Create user2's private template (not owned by user1, excluded by base query)
user2Private := &database.AgentTemplate{
Type: "langflow",
UserUUID: userUUID2,
Name: "User2 Private Template",
Content: "private",
Public: false,
}
_, err = store.Create(ctx, user2Private)
require.NoError(t, err)

// Editable=true should return only templates owned by user1
editableTrue := true
templates, total, err := store.ListByUserUUID(ctx, userUUID1, types.AgentTemplateFilter{Editable: &editableTrue}, 10, 1)
require.NoError(t, err)
require.Len(t, templates, 2)
require.Equal(t, 2, total)
for _, tmpl := range templates {
require.Equal(t, userUUID1, tmpl.UserUUID, "All templates should belong to user1 when Editable=true")
}

// Editable=false should return only public templates not owned by user1
editableFalse := false
templates, total, err = store.ListByUserUUID(ctx, userUUID1, types.AgentTemplateFilter{Editable: &editableFalse}, 10, 1)
require.NoError(t, err)
require.Len(t, templates, 1)
require.Equal(t, 1, total)
require.Equal(t, user2Public.ID, templates[0].ID, "Only user2's public template should be returned when Editable=false")

// Combined filter (Editable=true + Type)
templates, total, err = store.ListByUserUUID(ctx, userUUID1, types.AgentTemplateFilter{Editable: &editableTrue, Type: "langflow"}, 10, 1)
require.NoError(t, err)
require.Len(t, templates, 1)
require.Equal(t, 1, total)
require.Equal(t, user1Private.ID, templates[0].ID, "Only user1's private langflow template should be returned")

// Combined filter (Editable=false + Type)
templates, total, err = store.ListByUserUUID(ctx, userUUID1, types.AgentTemplateFilter{Editable: &editableFalse, Type: "agno"}, 10, 1)
require.NoError(t, err)
require.Len(t, templates, 1)
require.Equal(t, 1, total)
require.Equal(t, user2Public.ID, templates[0].ID, "Only user2's public agno template should be returned")

// Combined filter (Editable=true + Search)
templates, total, err = store.ListByUserUUID(ctx, userUUID1, types.AgentTemplateFilter{Editable: &editableTrue, Search: "Public"}, 10, 1)
require.NoError(t, err)
require.Len(t, templates, 1)
require.Equal(t, 1, total)
require.Equal(t, user1Public.ID, templates[0].ID, "Only user1's public template should match the search")
}
6 changes: 4 additions & 2 deletions common/types/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,17 @@ type AgentTemplate struct {
Description *string `json:"description" binding:"omitempty,max=500"` // Agent template description
Content *string `json:"content,omitempty"` // Used to store the complete content of the template
Public *bool `json:"public,omitempty"` // Whether the template is public
Editable bool `json:"editable"` // Whether the template is editable (only the owner can delete)
Metadata *map[string]any `json:"metadata,omitempty"` // Template metadata
IsPinned bool `json:"is_pinned"` // Whether the template is pinned by the user
CreatedAt time.Time `json:"created_at"` // When the template was created
UpdatedAt time.Time `json:"updated_at"` // When the template was last updated
}

type AgentTemplateFilter struct {
Search string
Type string
Search string
Type string
Editable *bool
}

// AgentInstance represents an instance created from an agent template
Expand Down
Loading