refactor(permissions): remove auto-add file writer, add config type constants

- Remove auto-add logic that granted file_writer permission to the first
  group/guild member who chatted with the bot
- Add ConfigTypeFileWriter and ConfigTypeHeartbeat constants, replace all
  hardcoded config_type strings across callers
- Add bootstrap exception: /addwriter and !addwriter allow first writer
  to be added when no writers exist yet
- Optimize writer commands: reuse cached ListFileWriters result for both
  permission check and last-writer guard, reducing DB queries per command
- Add freshness directive to file writer system prompt so bot prioritizes
  current list over stale references in conversation history
This commit is contained in:
viettranx committed 2026-04-01 13:59:56 +07:00
1 parent f4369c51e4
commit 39bb90bd60
10 files changed
+70 -80

No files matched your search

+1 -29
View File
@@ -2,9 +2,6 @@ package cmd
import (
"context"
"encoding/json"
"log/slog"
"strings"
"github.com/google/uuid"
@@ -17,38 +14,13 @@ import (
// buildEnsureUserProfile creates the user profile resolution callback.
// Creates/resolves user profile and returns effective workspace.
// Separated from seeding to allow independent lifecycle management.
func buildEnsureUserProfile(as store.AgentStore, configPermStore store.ConfigPermissionStore) agent.EnsureUserProfileFunc {
func buildEnsureUserProfile(as store.AgentStore) agent.EnsureUserProfileFunc {
return func(ctx context.Context, agentID uuid.UUID, userID, workspace, channel string) (string, bool, error) {
isNew, effectiveWs, err := as.GetOrCreateUserProfile(ctx, agentID, userID, workspace, channel)
if err != nil {
return effectiveWs, false, err
}
// Auto-add first group member as a file writer (bootstrap the allowlist).
// Only needed for truly new profiles — existing groups already have their writers.
if isNew && configPermStore != nil && (strings.HasPrefix(userID, "group:") || strings.HasPrefix(userID, "guild:")) {
senderID := store.SenderIDFromContext(ctx)
if senderID != "" {
parts := strings.SplitN(senderID, "|", 2)
numericID := parts[0]
senderUsername := ""
if len(parts) > 1 {
senderUsername = parts[1]
}
meta, _ := json.Marshal(map[string]string{"displayName": "", "username": senderUsername})
if addErr := configPermStore.Grant(ctx, &store.ConfigPermission{
AgentID: agentID,
Scope: userID,
ConfigType: "file_writer",
UserID: numericID,
Permission: "allow",
Metadata: meta,
}); addErr != nil {
slog.Warn("failed to auto-add group file writer", "error", addErr, "sender", numericID, "group", userID)
}
}
}
return effectiveWs, isNew, nil
}
}
+1 -1
View File
@@ -94,7 +94,7 @@ func wireExtras(
var ensureUserProfile agent.EnsureUserProfileFunc
var seedUserFiles agent.SeedUserFilesFunc
if stores.Agents != nil {
ensureUserProfile = buildEnsureUserProfile(stores.Agents, stores.ConfigPermissions)
ensureUserProfile = buildEnsureUserProfile(stores.Agents)
seedUserFiles = buildSeedUserFiles(stores.Agents)
}