-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmessage.py
More file actions
73 lines (55 loc) · 2.09 KB
/
Copy pathmessage.py
File metadata and controls
73 lines (55 loc) · 2.09 KB
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
"""Message types used across every pattern.
Two distinct concepts live here, and keeping them separate is half the
point of the whole repo:
* ``Message`` — a single turn in an LLM conversation (system/user/assistant/
tool). This is what you send *to a model*.
* ``Envelope`` — an agent-to-agent (A2A) message that travels *between
agents* over a bus or a direct handoff. It carries routing metadata
(sender, recipient, intent) that an LLM message does not.
Confusing the two is the most common mistake people make when they start
wiring agents together, so we model them as different classes on purpose.
"""
from __future__ import annotations
import itertools
from dataclasses import dataclass, field
from enum import Enum
from typing import Any
_envelope_ids = itertools.count(1)
class Role(str, Enum):
"""Standard chat roles (OpenAI/Groq compatible)."""
SYSTEM = "system"
USER = "user"
ASSISTANT = "assistant"
TOOL = "tool"
@dataclass
class Message:
"""One turn in an LLM conversation."""
role: Role
content: str
name: str | None = None
def to_openai(self) -> dict[str, Any]:
"""Serialize to the dict shape Groq/OpenAI chat endpoints expect."""
payload: dict[str, Any] = {"role": self.role.value, "content": self.content}
if self.name:
payload["name"] = self.name
return payload
@dataclass
class Envelope:
"""An agent-to-agent message.
``recipient`` doubles as a *topic* on the message bus, so the same
envelope works for direct handoffs and pub/sub fan-out.
"""
sender: str
recipient: str
intent: str # e.g. "request", "result", "handoff", "critique"
payload: Any
reply_to: str | None = None
id: str = field(default_factory=lambda: f"env-{next(_envelope_ids)}")
def __repr__(self) -> str: # pragma: no cover - cosmetic
preview = str(self.payload)
if len(preview) > 60:
preview = preview[:57] + "..."
return (
f"Envelope({self.id} {self.sender}->{self.recipient} "
f"intent={self.intent!r} payload={preview!r})"
)