Files
anti f2b3393669 chore: relicense to AGPL-3.0-or-later and add SPDX headers
Replaces LICENSE (GPLv3 -> AGPLv3) and prepends
`SPDX-License-Identifier: AGPL-3.0-or-later` to every source file
across decnet/, decnet_web/, tests/, scripts/, and tools/.

Rationale: closes the GPLv3 ASP loophole so any party operating a
modified DECNET as a network service must offer their modified
source. Personal copyright (Samuel Paschuan) + inbound=outbound
contributions make a future unilateral relicense infeasible.

- LICENSE: full AGPL-3.0 text (gnu.org/licenses/agpl-3.0.txt)
- COPYRIGHT: project copyright notice
- tools/add_spdx_headers.py: idempotent header injector
  (shebang- and PEP 263-aware)

Touches 1565 source files (.py, .ts, .tsx, .js, .jsx, .css, .sh).
No behavior change; comments only.
2026-05-22 21:04:16 -04:00

51 lines
1.9 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""DB-row + bus-topic helpers for the emailgen worker.
Mirror of :mod:`decnet.orchestrator.events` for the email action class.
Kept in its own module so the SSH-flavoured orchestrator and the
emailgen worker don't accumulate cross-imports of each other's action
types.
"""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any
from decnet.bus import topics as _topics
from decnet.orchestrator.drivers.base import ActivityResult
from decnet.orchestrator.emailgen.scheduler import EmailAction
def to_row(action: EmailAction, result: ActivityResult) -> dict[str, Any]:
"""Build the kwargs dict for ``OrchestratorEmail(**...)``.
Pulls ``message_id`` / ``subject`` / ``language`` out of the
driver's ``payload`` rather than off the action — the EML's
Message-ID is generated inside the driver after the LLM call so
we know it matches what landed on disk.
"""
payload = result.payload or {}
return {
"ts": datetime.now(timezone.utc),
"mail_decky_uuid": action.mail_decky_uuid,
"thread_id": action.thread_id,
"message_id": payload.get("message_id", ""),
"in_reply_to": action.parent_message_id,
"sender_email": action.sender.email,
"recipient_email": action.recipient.email,
"subject": payload.get("subject", ""),
"language": payload.get("language", action.sender.language or "en"),
"eml_path": payload.get("eml_path", ""),
"success": result.success,
"payload": payload, # repo serialises dict→json
}
def topic_for(action: EmailAction) -> str:
"""Map an email action to its bus topic."""
return _topics.orchestrator(_topics.ORCHESTRATOR_EMAIL, action.mail_decky_uuid)
def event_type_for(action: EmailAction) -> str: # noqa: ARG001 — symmetry
return _topics.ORCHESTRATOR_EMAIL