1"""

2 AgentOS v0.70 — 插件系统: 注册中心。

3 基因来源: Docker插件体系 + VSCode扩展市场

4

5 插件清单格式:

6- manifest.json: 插件元数据

7- 入口点: Python类路径

8- 依赖声明: 插件间依赖

9"""

10

11 from __future__ import annotations

12

13 from dataclasses import dataclass, field

14 from enum import Enum

15 from typing import Any, Callable

16

17

18 class PluginType(str, Enum):

19 """插件类型枚举。"""

20 PROVIDER = "provider" # 模型provider (如GeminiAdapter)

21 TOOL = "tool" # 工具扩展

22 MIDDLEWARE = "middleware" # 请求/响应拦截器

23 SINK = "sink" # 输出后端 (观测/日志/存储)

24 HOOK = "hook" # 生命周期钩子

25 CUSTOM = "custom" # 自定义

26

27

28 class PluginStatus(str, Enum):

29

30 """插件状态。"""

31

32 LOADED = "loaded"

33 INITIALIZED = "initialized"

34 ACTIVE = "active"

35 STOPPING = "stopping"

36 STOPPED = "stopped"

37 ERROR = "error"

38

39

40@dataclass

41 class PluginManifest:

42 """插件清单 — 描述插件能力与依赖。"""

43

44 name: str

45 version: str

46 description: str = ""

47 author: str = ""

48 plugin_type: PluginType = PluginType.CUSTOM

49 entry_point: str = "" # fully qualified class path

50 dependencies: list[str] = field(default_factory=list)

51 optional_dependencies: list[str] = field(default_factory=list)

52 tags: list[str] = field(default_factory=list)

53 config_schema: dict = field(default_factory=dict)

54 priority: int = 50 # 0=最高, 100=最低

55 homepage: str = ""

56 license: str = "MIT"

57

58 def to_dict(self) -> dict:

59 return {

60 "name": self.name,

61 "version": self.version,

62 "plugin_type": self.plugin_type.value,

63 "entry_point": self.entry_point,

64 "dependencies": self.dependencies,

65 "tags": self.tags,

66 }

67

68

69@dataclass

70 class RegisteredPlugin:

71 """已注册的插件实例。"""

72

73 manifest: PluginManifest

74 instance: Any = None

75 status: PluginStatus = PluginStatus.LOADED

76 load_time_ms: float = 0.0

77 error: str | None = None

78

79

80 class PluginRegistry:

81 """

82 插件注册中心 — 统一管理所有已注册插件。

83 支持: CRUD、查询、按标签/类型检索、依赖解析。

84 """

85

86 def __init__(self):

87 self._plugins: dict[str, RegisteredPlugin] = {}

88 self._hooks: dict[str, list[Callable]] = {} # event → list of callbacks

89

90 # ── CRUD ─────────────────────────────────────

91

92 def register(self, manifest: PluginManifest, instance: Any = None) -> RegisteredPlugin:

93 """注册插件（覆盖已有同名插件）。"""

94 registered = RegisteredPlugin(manifest=manifest, instance=instance)

95 self._plugins[manifest.name] = registered

96 return registered

97

98 def unregister(self, name: str) -> bool:

99 if name in self._plugins:

100 del self._plugins[name]

101 return True

102 return False

103

104 def get(self, name: str) -> RegisteredPlugin | None:

105 return self._plugins.get(name)

106

107 def get_instance(self, name: str) -> Any:

108 """获取插件实例。"""

109 registered = self._plugins.get(name)

110 return registered.instance if registered else None

111

112 # ── Query ────────────────────────────────────

113

114 def list_all(self) -> list[RegisteredPlugin]:

115 return list(self._plugins.values())

116

117 def list_names(self) -> list[str]:

118 return list(self._plugins.keys())

119

120 def by_type(self, plugin_type: PluginType) -> list[RegisteredPlugin]:

121 return [p for p in self._plugins.values() if p.manifest.plugin_type == plugin_type]

122

123 def by_tag(self, tag: str) -> list[RegisteredPlugin]:

124 return [p for p in self._plugins.values() if tag in p.manifest.tags]

125

126 def by_status(self, status: PluginStatus) -> list[RegisteredPlugin]:

127 return [p for p in self._plugins.values() if p.status == status]

128

129 # ── Dependency Resolution ────────────────────

130

131 def resolve_order(self, names: list[str]) -> list[str]:

132 """拓扑排序解析插件加载顺序。"""

133 adj: dict[str, list[str]] = {n: [] for n in names}

134 for name in names:

135 p = self._plugins.get(name)

136 if p:

137 adj[name] = [d for d in p.manifest.dependencies if d in names]

138

139 # Kahn's algorithm

140 in_degree = {n: 0 for n in names}

141 for deps in adj.values():

142 for d in deps:

143 in_degree[d] += 1

144

145 queue = [n for n in names if in_degree[n] == 0]

146 order = []

147 while queue:

148 n = queue.pop(0)

149 order.append(n)

150 for dep in adj.get(n, []):

151 in_degree[dep] -= 1

152 if in_degree[dep] == 0:

153 queue.append(dep)

154

155 if len(order) != len(names):

156 missing = set(names) - set(order)

157 raise DependencyCycleError(f"循环依赖或缺失依赖: {missing}")

158

159 return order

160

161 def check_requirements(self, name: str) -> list[str]:

162 """检查某插件的依赖是否满足。返回缺失的依赖列表。"""

163 p = self._plugins.get(name)

164 if not p:

165 return [name]

166 missing = []

167 for dep in p.manifest.dependencies:

168 if dep not in self._plugins:

169 missing.append(dep)

170 return missing

171

172 # ── Hook System ──────────────────────────────

173

174 def register_hook(self, event: str, callback: Callable):

175 """注册事件钩子。"""

176 if event not in self._hooks:

177 self._hooks[event] = []

178 self._hooks[event].append(callback)

179

180 async def emit_hook(self, event: str, **kwargs) -> list[Any]:

181 """触发事件钩子，返回所有回调结果。"""

182 results = []

183 for cb in self._hooks.get(event, []):

184 try:

185 import asyncio

186 if asyncio.iscoroutinefunction(cb):

187 results.append(await cb(**kwargs))

188 else:

189 results.append(cb(**kwargs))

190 except Exception as e:

191 results.append({"error": str(e)})

192 return results

193

194 def hook_names(self) -> list[str]:

195 return list(self._hooks.keys())

196

197 # ── Info ─────────────────────────────────────

198

199 @property

200 def count(self) -> int:

201 return len(self._plugins)

202

203 def summary(self) -> str:

204 by_type = {}

205 for p in self._plugins.values():

206 t = p.manifest.plugin_type.value

207 by_type[t] = by_type.get(t, 0) + 1

208 lines = [f"共 {self.count} 个插件"]

209 for t, c in sorted(by_type.items()):

210 lines.append(f" {t}: {c}")

211 return "\n".join(lines)

212

213

214 class DependencyCycleError(Exception):

215

216 """插件依赖循环异常。"""

217

218 pass