feat(monitor): store plugin version separately from openclaw version

- Add server_states.plugin_version column
- Keep openclaw_version for remote OpenClaw runtime version
- Expose plugin_version in monitor server view
- Accept and persist plugin_version in heartbeat payloads
This commit is contained in:
zhi
2026-03-20 07:23:18 +00:00
parent a0d0c7b3a1
commit 97f12cac7a
4 changed files with 15 additions and 0 deletions

View File

@@ -198,6 +198,7 @@ def revoke_api_key(server_id: int, db: Session = Depends(get_db), _: models.User
class ServerHeartbeat(BaseModel):
identifier: str
openclaw_version: str | None = None
plugin_version: str | None = None
agents: List[dict] = []
cpu_pct: float | None = None
mem_pct: float | None = None
@@ -215,6 +216,7 @@ def server_heartbeat(payload: ServerHeartbeat, db: Session = Depends(get_db)):
st = ServerState(server_id=server.id)
db.add(st)
st.openclaw_version = payload.openclaw_version
st.plugin_version = payload.plugin_version
st.agents_json = json.dumps(payload.agents, ensure_ascii=False)
st.cpu_pct = payload.cpu_pct
st.mem_pct = payload.mem_pct
@@ -229,6 +231,7 @@ def server_heartbeat(payload: ServerHeartbeat, db: Session = Depends(get_db)):
class TelemetryPayload(BaseModel):
identifier: str
openclaw_version: str | None = None
plugin_version: str | None = None
agents: List[dict] = []
cpu_pct: float | None = None
mem_pct: float | None = None
@@ -256,6 +259,7 @@ def server_heartbeat_v2(
st = ServerState(server_id=server.id)
db.add(st)
st.openclaw_version = payload.openclaw_version
st.plugin_version = payload.plugin_version
st.agents_json = json.dumps(payload.agents, ensure_ascii=False)
st.cpu_pct = payload.cpu_pct
st.mem_pct = payload.mem_pct
@@ -328,12 +332,17 @@ async def server_ws(websocket: WebSocket):
if event == 'server.hello':
st.openclaw_version = payload.get('openclaw_version')
st.plugin_version = payload.get('plugin_version')
st.agents_json = json.dumps(payload.get('agents') or [], ensure_ascii=False)
elif event in {'server.metrics', 'agent.status_changed'}:
st.cpu_pct = payload.get('cpu_pct', st.cpu_pct)
st.mem_pct = payload.get('mem_pct', st.mem_pct)
st.disk_pct = payload.get('disk_pct', st.disk_pct)
st.swap_pct = payload.get('swap_pct', st.swap_pct)
if 'openclaw_version' in payload:
st.openclaw_version = payload.get('openclaw_version')
if 'plugin_version' in payload:
st.plugin_version = payload.get('plugin_version')
if 'agents' in payload:
st.agents_json = json.dumps(payload.get('agents') or [], ensure_ascii=False)

View File

@@ -220,6 +220,10 @@ def _migrate_schema():
db.execute(text("ALTER TABLE monitored_servers ADD COLUMN api_key VARCHAR(64) NULL"))
db.execute(text("CREATE UNIQUE INDEX idx_monitored_servers_api_key ON monitored_servers (api_key)"))
# --- server_states.plugin_version for monitor plugin telemetry ---
if _has_table(db, "server_states") and not _has_column(db, "server_states", "plugin_version"):
db.execute(text("ALTER TABLE server_states ADD COLUMN plugin_version VARCHAR(64) NULL"))
db.commit()
except Exception as e:
db.rollback()

View File

@@ -50,6 +50,7 @@ class ServerState(Base):
id = Column(Integer, primary_key=True, index=True)
server_id = Column(Integer, ForeignKey('monitored_servers.id'), nullable=False, unique=True)
openclaw_version = Column(String(64), nullable=True)
plugin_version = Column(String(64), nullable=True)
agents_json = Column(Text, nullable=True) # json list
cpu_pct = Column(Float, nullable=True)
mem_pct = Column(Float, nullable=True)

View File

@@ -298,6 +298,7 @@ def get_server_states_view(db: Session, offline_after_minutes: int = 7):
'display_name': s.display_name or s.identifier,
'online': online,
'openclaw_version': st.openclaw_version if st else None,
'plugin_version': st.plugin_version if st else None,
'cpu_pct': st.cpu_pct if st else None,
'mem_pct': st.mem_pct if st else None,
'disk_pct': st.disk_pct if st else None,