File size: 2,726 Bytes
fb4d8fe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import type { OpenClawConfig } from "../config/config.js";
import type { PluginSlotsConfig } from "../config/types.plugins.js";
import type { PluginKind } from "./types.js";

export type PluginSlotKey = keyof PluginSlotsConfig;

type SlotPluginRecord = {
  id: string;
  kind?: PluginKind;
};

const SLOT_BY_KIND: Record<PluginKind, PluginSlotKey> = {
  memory: "memory",
};

const DEFAULT_SLOT_BY_KEY: Record<PluginSlotKey, string> = {
  memory: "memory-core",
};

export function slotKeyForPluginKind(kind?: PluginKind): PluginSlotKey | null {
  if (!kind) {
    return null;
  }
  return SLOT_BY_KIND[kind] ?? null;
}

export function defaultSlotIdForKey(slotKey: PluginSlotKey): string {
  return DEFAULT_SLOT_BY_KEY[slotKey];
}

export type SlotSelectionResult = {
  config: OpenClawConfig;
  warnings: string[];
  changed: boolean;
};

export function applyExclusiveSlotSelection(params: {
  config: OpenClawConfig;
  selectedId: string;
  selectedKind?: PluginKind;
  registry?: { plugins: SlotPluginRecord[] };
}): SlotSelectionResult {
  const slotKey = slotKeyForPluginKind(params.selectedKind);
  if (!slotKey) {
    return { config: params.config, warnings: [], changed: false };
  }

  const warnings: string[] = [];
  const pluginsConfig = params.config.plugins ?? {};
  const prevSlot = pluginsConfig.slots?.[slotKey];
  const slots = {
    ...pluginsConfig.slots,
    [slotKey]: params.selectedId,
  };

  const inferredPrevSlot = prevSlot ?? defaultSlotIdForKey(slotKey);
  if (inferredPrevSlot && inferredPrevSlot !== params.selectedId) {
    warnings.push(
      `Exclusive slot "${slotKey}" switched from "${inferredPrevSlot}" to "${params.selectedId}".`,
    );
  }

  const entries = { ...pluginsConfig.entries };
  const disabledIds: string[] = [];
  if (params.registry) {
    for (const plugin of params.registry.plugins) {
      if (plugin.id === params.selectedId) {
        continue;
      }
      if (plugin.kind !== params.selectedKind) {
        continue;
      }
      const entry = entries[plugin.id];
      if (!entry || entry.enabled !== false) {
        entries[plugin.id] = {
          ...entry,
          enabled: false,
        };
        disabledIds.push(plugin.id);
      }
    }
  }

  if (disabledIds.length > 0) {
    warnings.push(
      `Disabled other "${slotKey}" slot plugins: ${disabledIds.toSorted().join(", ")}.`,
    );
  }

  const changed = prevSlot !== params.selectedId || disabledIds.length > 0;

  if (!changed) {
    return { config: params.config, warnings: [], changed: false };
  }

  return {
    config: {
      ...params.config,
      plugins: {
        ...pluginsConfig,
        slots,
        entries,
      },
    },
    warnings,
    changed: true,
  };
}