feat(swarm): DeckyConfig.host_uuid + fix agent log/status field refs

- decnet.models.DeckyConfig grows an optional 'host_uuid' (the SwarmHost
  that runs this decky). Defaults to None so legacy unihost state files
  deserialize unchanged.
- decnet.agent.executor: replace non-existent config.name references
  with config.mode / config.interface in logs and status payload.
- tests/swarm/test_state_schema.py covers legacy-dict roundtrip, field
  default, and swarm-mode assignments.
This commit is contained in:
2026-04-18 19:10:25 -04:00
parent 0c77cdab32
commit cd0057c129
3 changed files with 68 additions and 2 deletions

View File

@@ -21,7 +21,10 @@ log = get_logger("agent.executor")
async def deploy(config: DecnetConfig, dry_run: bool = False, no_cache: bool = False) -> None:
"""Run the blocking deployer off-loop. The deployer itself calls
save_state() internally once the compose file is materialised."""
log.info("agent.deploy name=%s deckies=%d", config.name, len(config.deckies))
log.info(
"agent.deploy mode=%s deckies=%d interface=%s",
config.mode, len(config.deckies), config.interface,
)
await asyncio.to_thread(_deployer.deploy, config, dry_run, no_cache, False)
@@ -39,7 +42,7 @@ async def status() -> dict[str, Any]:
config, _compose_path = state
return {
"deployed": True,
"name": getattr(config, "name", None),
"mode": config.mode,
"compose_path": str(_compose_path),
"deckies": [d.model_dump() for d in config.deckies],
}

View File

@@ -99,6 +99,9 @@ class DeckyConfig(BaseModel):
mutate_interval: int | None = None # automatic rotation interval in minutes
last_mutated: float = 0.0 # timestamp of last mutation
last_login_attempt: float = 0.0 # timestamp of most recent interaction
# SWARM: the SwarmHost.uuid that runs this decky. None in unihost mode
# so existing state files deserialize unchanged.
host_uuid: str | None = None
@field_validator("services")
@classmethod