flux-vm 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. flux/__init__.py +8 -0
  2. flux/__main__.py +6 -0
  3. flux/a2a/__init__.py +44 -0
  4. flux/a2a/coordinator.py +165 -0
  5. flux/a2a/messages.py +171 -0
  6. flux/a2a/primitives.py +730 -0
  7. flux/a2a/signal_compiler.py +465 -0
  8. flux/a2a/transport.py +81 -0
  9. flux/a2a/trust.py +363 -0
  10. flux/adaptive/__init__.py +59 -0
  11. flux/adaptive/compiler_bridge.py +284 -0
  12. flux/adaptive/profiler.py +441 -0
  13. flux/adaptive/selector.py +430 -0
  14. flux/asm/__init__.py +30 -0
  15. flux/asm/binary_patcher.py +243 -0
  16. flux/asm/cross_assembler.py +596 -0
  17. flux/asm/elf_header.py +369 -0
  18. flux/asm/errors.py +112 -0
  19. flux/asm/linker.py +247 -0
  20. flux/asm/macros.py +334 -0
  21. flux/asm/opcodes_compat.py +254 -0
  22. flux/bytecode/__init__.py +36 -0
  23. flux/bytecode/decoder.py +384 -0
  24. flux/bytecode/encoder.py +444 -0
  25. flux/bytecode/formats.py +249 -0
  26. flux/bytecode/isa_unified.py +462 -0
  27. flux/bytecode/opcodes.py +261 -0
  28. flux/bytecode/opcodes_legacy.py +234 -0
  29. flux/bytecode/validator.py +316 -0
  30. flux/cli.py +1120 -0
  31. flux/compiler/__init__.py +0 -0
  32. flux/compiler/pipeline.py +96 -0
  33. flux/cost/__init__.py +24 -0
  34. flux/cost/energy.py +216 -0
  35. flux/cost/model.py +289 -0
  36. flux/creative/__init__.py +59 -0
  37. flux/creative/generative.py +573 -0
  38. flux/creative/live.py +439 -0
  39. flux/creative/sonification.py +445 -0
  40. flux/creative/visualization.py +279 -0
  41. flux/debugger.py +644 -0
  42. flux/disasm.py +456 -0
  43. flux/docs/__init__.py +33 -0
  44. flux/docs/generator.py +330 -0
  45. flux/docs/introspector.py +386 -0
  46. flux/docs/renderer.py +284 -0
  47. flux/docs/stats.py +261 -0
  48. flux/evolution/__init__.py +76 -0
  49. flux/evolution/evolution.py +425 -0
  50. flux/evolution/genome.py +733 -0
  51. flux/evolution/mutator.py +452 -0
  52. flux/evolution/pattern_mining.py +402 -0
  53. flux/evolution/validator.py +394 -0
  54. flux/fir/__init__.py +94 -0
  55. flux/fir/blocks.py +45 -0
  56. flux/fir/builder.py +255 -0
  57. flux/fir/instructions.py +606 -0
  58. flux/fir/printer.py +273 -0
  59. flux/fir/types.py +174 -0
  60. flux/fir/validator.py +211 -0
  61. flux/fir/values.py +22 -0
  62. flux/flywheel/__init__.py +59 -0
  63. flux/flywheel/engine.py +787 -0
  64. flux/flywheel/hypothesis.py +280 -0
  65. flux/flywheel/knowledge.py +435 -0
  66. flux/flywheel/metrics.py +215 -0
  67. flux/frontend/__init__.py +0 -0
  68. flux/frontend/c_frontend.py +842 -0
  69. flux/frontend/python_frontend.py +585 -0
  70. flux/jit/__init__.py +33 -0
  71. flux/jit/cache.py +187 -0
  72. flux/jit/compiler.py +356 -0
  73. flux/jit/ir_optimize.py +547 -0
  74. flux/jit/tracing.py +339 -0
  75. flux/mega/__init__.py +34 -0
  76. flux/mega/conductor.py +855 -0
  77. flux/mega/demo_mega.py +93 -0
  78. flux/memory/__init__.py +46 -0
  79. flux/memory/bandit.py +275 -0
  80. flux/memory/experience.py +429 -0
  81. flux/memory/learning.py +273 -0
  82. flux/memory/store.py +602 -0
  83. flux/migrate/__init__.py +10 -0
  84. flux/migrate/migrator.py +754 -0
  85. flux/migrate/report.py +124 -0
  86. flux/modules/__init__.py +48 -0
  87. flux/modules/card.py +117 -0
  88. flux/modules/container.py +316 -0
  89. flux/modules/granularity.py +128 -0
  90. flux/modules/namespace.py +87 -0
  91. flux/modules/reloader.py +322 -0
  92. flux/open_interp/__init__.py +16 -0
  93. flux/open_interp/argumentation.py +332 -0
  94. flux/open_interp/assembler.py +133 -0
  95. flux/open_interp/beachcomb.py +480 -0
  96. flux/open_interp/compiler.py +190 -0
  97. flux/open_interp/context_filter.py +62 -0
  98. flux/open_interp/contradiction_detector.py +311 -0
  99. flux/open_interp/decomposer.py +657 -0
  100. flux/open_interp/edge_profile.py +169 -0
  101. flux/open_interp/ethical_weight.py +49 -0
  102. flux/open_interp/ghost_loader.py +546 -0
  103. flux/open_interp/interpreter.py +257 -0
  104. flux/open_interp/l0_scrubber.py +487 -0
  105. flux/open_interp/necrosis_detector.py +128 -0
  106. flux/open_interp/paper_bridge.py +276 -0
  107. flux/open_interp/paper_decomposer.py +367 -0
  108. flux/open_interp/pruning.py +533 -0
  109. flux/open_interp/sandbox.py +141 -0
  110. flux/open_interp/semantic_router.py +282 -0
  111. flux/open_interp/term_obituary.py +173 -0
  112. flux/open_interp/tiling.py +327 -0
  113. flux/open_interp/vocab_signal.py +325 -0
  114. flux/open_interp/vocabulary.py +217 -0
  115. flux/open_interpreter.py +986 -0
  116. flux/optimizer/__init__.py +17 -0
  117. flux/optimizer/passes.py +105 -0
  118. flux/optimizer/pipeline.py +40 -0
  119. flux/parser/__init__.py +35 -0
  120. flux/parser/nodes.py +111 -0
  121. flux/parser/parser.py +437 -0
  122. flux/pipeline/__init__.py +20 -0
  123. flux/pipeline/debug.py +479 -0
  124. flux/pipeline/e2e.py +258 -0
  125. flux/pipeline/polyglot.py +234 -0
  126. flux/protocol/__init__.py +58 -0
  127. flux/protocol/channel.py +361 -0
  128. flux/protocol/message.py +323 -0
  129. flux/protocol/negotiation.py +367 -0
  130. flux/protocol/registry.py +242 -0
  131. flux/protocol/serialization.py +284 -0
  132. flux/py.typed +0 -0
  133. flux/reload/__init__.py +5 -0
  134. flux/reload/hot_loader.py +127 -0
  135. flux/repl.py +415 -0
  136. flux/retro/__init__.py +30 -0
  137. flux/retro/catalog.py +450 -0
  138. flux/retro/implementations/__init__.py +43 -0
  139. flux/retro/implementations/_asm.py +220 -0
  140. flux/retro/implementations/_builder.py +170 -0
  141. flux/retro/implementations/game_of_life.py +282 -0
  142. flux/retro/implementations/lunar_lander.py +241 -0
  143. flux/retro/implementations/mandelbrot.py +225 -0
  144. flux/retro/implementations/markov_text.py +220 -0
  145. flux/retro/implementations/mastermind.py +318 -0
  146. flux/retro/implementations/pong.py +239 -0
  147. flux/retro/implementations/snake.py +350 -0
  148. flux/retro/implementations/tetris.py +307 -0
  149. flux/retro/implementations/text_adventure.py +272 -0
  150. flux/retro/implementations/tic_tac_toe.py +262 -0
  151. flux/retro/research/__init__.py +22 -0
  152. flux/retro/research/metrics.py +115 -0
  153. flux/retro/research/runner.py +247 -0
  154. flux/retro/research/session.py +471 -0
  155. flux/retro/showcase/__init__.py +215 -0
  156. flux/retro/showcase/__main__.py +3 -0
  157. flux/reverse/__init__.py +32 -0
  158. flux/reverse/code_map.py +176 -0
  159. flux/reverse/engineer.py +302 -0
  160. flux/reverse/parsers/__init__.py +6 -0
  161. flux/reverse/parsers/c_reverse.py +583 -0
  162. flux/reverse/parsers/python_reverse.py +720 -0
  163. flux/runtime/__init__.py +16 -0
  164. flux/runtime/agent.py +138 -0
  165. flux/runtime/agent_runtime.py +206 -0
  166. flux/schema/__init__.py +51 -0
  167. flux/schema/architecture.py +502 -0
  168. flux/schema/builder_schema.py +372 -0
  169. flux/schema/opcode_schema.py +203 -0
  170. flux/schema/tile_schema.py +659 -0
  171. flux/security/__init__.py +11 -0
  172. flux/security/bytecode_verifier.py +699 -0
  173. flux/security/capabilities.py +121 -0
  174. flux/security/resource_limits.py +52 -0
  175. flux/security/sandbox.py +59 -0
  176. flux/simulation/__init__.py +60 -0
  177. flux/simulation/digital_twin.py +838 -0
  178. flux/simulation/oracle.py +484 -0
  179. flux/simulation/predictor.py +401 -0
  180. flux/simulation/speculator.py +344 -0
  181. flux/stdlib/__init__.py +67 -0
  182. flux/stdlib/agents.py +238 -0
  183. flux/stdlib/collections.py +379 -0
  184. flux/stdlib/intrinsics.py +231 -0
  185. flux/stdlib/math.py +271 -0
  186. flux/stdlib/strings.py +159 -0
  187. flux/swarm/__init__.py +62 -0
  188. flux/swarm/agent.py +432 -0
  189. flux/swarm/deadlock.py +360 -0
  190. flux/swarm/message_bus.py +286 -0
  191. flux/swarm/swarm.py +493 -0
  192. flux/swarm/topology.py +297 -0
  193. flux/synthesis/__init__.py +30 -0
  194. flux/synthesis/demo.py +182 -0
  195. flux/synthesis/report.py +363 -0
  196. flux/synthesis/synthesizer.py +639 -0
  197. flux/tiles/__init__.py +39 -0
  198. flux/tiles/graph.py +277 -0
  199. flux/tiles/library.py +1078 -0
  200. flux/tiles/ports.py +84 -0
  201. flux/tiles/registry.py +176 -0
  202. flux/tiles/tile.py +237 -0
  203. flux/types/__init__.py +41 -0
  204. flux/types/compat.py +179 -0
  205. flux/types/generic.py +343 -0
  206. flux/types/unify.py +826 -0
  207. flux/vm/__init__.py +37 -0
  208. flux/vm/evolution.py +292 -0
  209. flux/vm/interpreter.py +1598 -0
  210. flux/vm/memory.py +155 -0
  211. flux/vm/registers.py +156 -0
  212. flux_vm-0.1.0.dist-info/METADATA +415 -0
  213. flux_vm-0.1.0.dist-info/RECORD +217 -0
  214. flux_vm-0.1.0.dist-info/WHEEL +5 -0
  215. flux_vm-0.1.0.dist-info/entry_points.txt +2 -0
  216. flux_vm-0.1.0.dist-info/licenses/LICENSE +21 -0
  217. flux_vm-0.1.0.dist-info/top_level.txt +1 -0
flux/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ """FLUX — Fluid Language Universal eXecution.
2
+
3
+ A Self-Assembling, Self-Improving Runtime for Agent-First Code.
4
+ """
5
+
6
+ __version__ = "0.1.0"
7
+ __author__ = "SuperInstance"
8
+ __license__ = "MIT"
flux/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Allow running FLUX as ``python -m flux``."""
2
+
3
+ from flux.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
flux/a2a/__init__.py ADDED
@@ -0,0 +1,44 @@
1
+ """FLUX A2A Protocol Layer — Agent-to-Agent communication primitives.
2
+
3
+ This package provides:
4
+ - ``messages`` — Binary A2A message types (A2AMessage with 52-byte header)
5
+ - ``transport`` — Local in-process message delivery (LocalTransport)
6
+ - ``trust`` — INCREMENTS+2 trust engine (TrustEngine, InteractionRecord, AgentProfile)
7
+ - ``coordinator`` — Multi-agent orchestration (AgentCoordinator)
8
+ - ``primitives`` — Rich protocol primitives (Branch, Fork, CoIterate, Discuss, Synthesize, Reflect)
9
+ """
10
+
11
+ from flux.a2a.messages import A2AMessage
12
+ from flux.a2a.transport import LocalTransport
13
+ from flux.a2a.trust import InteractionRecord, AgentProfile, TrustEngine
14
+ from flux.a2a.coordinator import AgentCoordinator
15
+ from flux.a2a.primitives import (
16
+ BranchPrimitive, BranchBody,
17
+ ForkPrimitive, ForkInherit, ForkMutation,
18
+ CoIteratePrimitive,
19
+ DiscussPrimitive, Participant,
20
+ SynthesizePrimitive, SynthesisSource,
21
+ ReflectPrimitive,
22
+ parse_primitive,
23
+ )
24
+
25
+ __all__ = [
26
+ # Messages
27
+ "A2AMessage",
28
+ # Transport
29
+ "LocalTransport",
30
+ # Trust
31
+ "InteractionRecord",
32
+ "AgentProfile",
33
+ "TrustEngine",
34
+ # Coordinator
35
+ "AgentCoordinator",
36
+ # Protocol Primitives (Phase 1: adopted from flux-a2a-prototype)
37
+ "BranchPrimitive", "BranchBody",
38
+ "ForkPrimitive", "ForkInherit", "ForkMutation",
39
+ "CoIteratePrimitive",
40
+ "DiscussPrimitive", "Participant",
41
+ "SynthesizePrimitive", "SynthesisSource",
42
+ "ReflectPrimitive",
43
+ "parse_primitive",
44
+ ]
@@ -0,0 +1,165 @@
1
+ """Agent Coordinator — Orchestrates multiple agents within a single VM.
2
+
3
+ Ties together :class:`LocalTransport` for message delivery and
4
+ :class:`TrustEngine` for trust-gated communication. Agents are
5
+ identified by string names; internally each is assigned a ``uuid.UUID``
6
+ for the A2A protocol layer.
7
+
8
+ Message flow:
9
+
10
+ agent_a.send_message("bob", TELL, payload=b"hi")
11
+ → trust check (compute_trust >= threshold)
12
+ → build A2AMessage
13
+ → transport.send(message)
14
+ → message lands in bob's mailbox
15
+ → agent_b.get_messages("bob") drains the mailbox
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from typing import Any, Dict, List, Optional
21
+
22
+ import uuid
23
+
24
+ from flux.a2a.messages import A2AMessage
25
+ from flux.a2a.transport import LocalTransport
26
+ from flux.a2a.trust import TrustEngine
27
+
28
+
29
+ class AgentCoordinator:
30
+ """Coordinates multiple agents running in the same VM.
31
+
32
+ Parameters
33
+ ----------
34
+ trust_threshold : float
35
+ Minimum trust score required for message delivery (default 0.3).
36
+ """
37
+
38
+ def __init__(self, trust_threshold: float = 0.3) -> None:
39
+ self._agents: Dict[str, Dict[str, Any]] = {}
40
+ self.trust: TrustEngine = TrustEngine()
41
+ self.transport: LocalTransport = LocalTransport()
42
+ self.trust_threshold: float = trust_threshold
43
+
44
+ # ── Agent Registration ────────────────────────────────────────────────
45
+
46
+ def register_agent(
47
+ self, agent_id: str, interpreter: Any = None
48
+ ) -> uuid.UUID:
49
+ """Register an agent with an optional VM interpreter.
50
+
51
+ Parameters
52
+ ----------
53
+ agent_id : str
54
+ Logical name for the agent.
55
+ interpreter : Any, optional
56
+ A :class:`flux.vm.interpreter.Interpreter` instance, or None.
57
+
58
+ Returns
59
+ -------
60
+ uuid.UUID
61
+ The generated UUID for this agent (used in A2A headers).
62
+ """
63
+ aid = uuid.uuid4()
64
+ self.transport.register(aid)
65
+ self._agents[agent_id] = {
66
+ "uuid": aid,
67
+ "interpreter": interpreter,
68
+ }
69
+ return aid
70
+
71
+ def unregister_agent(self, agent_id: str) -> None:
72
+ """Remove an agent from the coordinator."""
73
+ info = self._agents.pop(agent_id, None)
74
+ if info is not None:
75
+ self.transport.unregister(info["uuid"])
76
+
77
+ # ── Messaging ─────────────────────────────────────────────────────────
78
+
79
+ def send_message(
80
+ self,
81
+ sender: str,
82
+ receiver: str,
83
+ msg_type: int,
84
+ payload: bytes = b"",
85
+ priority: int = 5,
86
+ in_reply_to: Optional[uuid.UUID] = None,
87
+ ) -> bool:
88
+ """Send an A2A message between registered agents.
89
+
90
+ The message is only delivered if the trust score from *sender*
91
+ to *receiver* meets the configured threshold.
92
+
93
+ Parameters
94
+ ----------
95
+ sender : str
96
+ Name of the sending agent.
97
+ receiver : str
98
+ Name of the receiving agent.
99
+ msg_type : int
100
+ A2A message type (0x60–0x7B).
101
+ payload : bytes
102
+ Application-level payload.
103
+ priority : int
104
+ Delivery priority 0–15.
105
+ in_reply_to : uuid.UUID, optional
106
+ UUID this message is replying to.
107
+
108
+ Returns
109
+ -------
110
+ bool
111
+ ``True`` if the message was delivered, ``False`` if blocked
112
+ by the trust gate or if either agent is unknown.
113
+ """
114
+ # Trust gate
115
+ trust = self.trust.compute_trust(sender, receiver)
116
+ if trust < self.trust_threshold:
117
+ return False
118
+
119
+ sender_info = self._agents.get(sender)
120
+ receiver_info = self._agents.get(receiver)
121
+ if sender_info is None or receiver_info is None:
122
+ return False
123
+
124
+ msg = A2AMessage(
125
+ sender=sender_info["uuid"],
126
+ receiver=receiver_info["uuid"],
127
+ conversation_id=uuid.uuid4(),
128
+ in_reply_to=in_reply_to,
129
+ message_type=msg_type,
130
+ priority=priority,
131
+ trust_token=int(trust * 1e9),
132
+ capability_token=0,
133
+ payload=payload,
134
+ )
135
+
136
+ delivered = self.transport.send(msg)
137
+ if delivered:
138
+ # Record positive interaction on success
139
+ self.trust.record_interaction(sender, receiver, True, 0.1)
140
+ return delivered
141
+
142
+ def get_messages(self, agent_id: str) -> List[A2AMessage]:
143
+ """Drain the mailbox for *agent_id* and return all pending messages."""
144
+ info = self._agents.get(agent_id)
145
+ if info is None:
146
+ return []
147
+ return self.transport.receive(info["uuid"])
148
+
149
+ def pending_count(self, agent_id: str) -> int:
150
+ """Return the number of pending messages for *agent_id*."""
151
+ info = self._agents.get(agent_id)
152
+ if info is None:
153
+ return 0
154
+ return self.transport.pending_count(info["uuid"])
155
+
156
+ # ── Queries ───────────────────────────────────────────────────────────
157
+
158
+ def get_agent_uuid(self, agent_name: str) -> Optional[uuid.UUID]:
159
+ """Return the UUID for a named agent, or ``None``."""
160
+ info = self._agents.get(agent_name)
161
+ return info["uuid"] if info else None
162
+
163
+ def registered_agents(self) -> List[str]:
164
+ """Return a list of all registered agent names."""
165
+ return list(self._agents.keys())
flux/a2a/messages.py ADDED
@@ -0,0 +1,171 @@
1
+ """A2A Message Types — Fixed-format binary messages for agent-to-agent communication.
2
+
3
+ Message layout (binary, 52-byte header):
4
+
5
+ Offset Size Field
6
+ ─────── ────── ──────────────────────────────────────
7
+ 0 16 sender_uuid (128-bit UUID)
8
+ 16 16 receiver_uuid (128-bit UUID)
9
+ 32 8 conversation_id (compact 64-bit)
10
+ 40 1 message_type (uint8, 0x60–0x7B)
11
+ 41 1 priority (uint8, 0–15)
12
+ 42 4 trust_token (uint32 LE)
13
+ 46 4 capability_token (uint32 LE)
14
+ 50 2 in_reply_to (uint16 LE, 0 = None)
15
+ 52 var payload (arbitrary bytes)
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import struct
21
+ import uuid
22
+ from dataclasses import dataclass, field
23
+ from typing import Optional
24
+
25
+ # Header format: <16s16s8sBBIIH = 16+16+8+1+1+4+4+2 = 52
26
+ _HEADER_STRUCT = struct.Struct("<16s16s8sBBIIH")
27
+
28
+
29
+ # ── A2A Message ───────────────────────────────────────────────────────────
30
+
31
+
32
+ @dataclass
33
+ class A2AMessage:
34
+ """Fixed-format binary A2A message with a 52-byte header.
35
+
36
+ Attributes
37
+ ----------
38
+ sender : uuid.UUID
39
+ 128-bit UUID of the originating agent.
40
+ receiver : uuid.UUID
41
+ 128-bit UUID of the target agent.
42
+ conversation_id : uuid.UUID
43
+ 128-bit UUID grouping related messages. Serialized as the first
44
+ 8 bytes (time_low + time_mid) for compactness; zero-padded on
45
+ deserialization.
46
+ in_reply_to : Optional[uuid.UUID]
47
+ When set, marks this message as a reply. Serialized as a uint16
48
+ extracted from the UUID bytes; deserialized as None when zero.
49
+ message_type : int
50
+ Protocol verb in range 0x60–0x7B (A2A opcode space).
51
+ priority : int
52
+ Delivery priority 0–15.
53
+ trust_token : int
54
+ 32-bit unsigned trust evidence token.
55
+ capability_token : int
56
+ 32-bit unsigned capability evidence token.
57
+ payload : bytes
58
+ Arbitrary application-level payload.
59
+ """
60
+
61
+ sender: uuid.UUID
62
+ receiver: uuid.UUID
63
+ conversation_id: uuid.UUID
64
+ in_reply_to: Optional[uuid.UUID]
65
+ message_type: int
66
+ priority: int
67
+ trust_token: int
68
+ capability_token: int
69
+ payload: bytes = b""
70
+
71
+ HEADER_SIZE: int = 52 # fixed header length in bytes
72
+
73
+ # ── Validation helpers ────────────────────────────────────────────────
74
+
75
+ def __post_init__(self) -> None:
76
+ if not (0x60 <= self.message_type <= 0x7B):
77
+ raise ValueError(
78
+ f"message_type must be in 0x60–0x7B, got 0x{self.message_type:02X}"
79
+ )
80
+ if not (0 <= self.priority <= 15):
81
+ raise ValueError(
82
+ f"priority must be 0–15, got {self.priority}"
83
+ )
84
+ if not (0 <= self.trust_token <= 0xFFFFFFFF):
85
+ raise ValueError(
86
+ f"trust_token must fit in uint32, got {self.trust_token}"
87
+ )
88
+ if not (0 <= self.capability_token <= 0xFFFFFFFF):
89
+ raise ValueError(
90
+ f"capability_token must fit in uint32, got {self.capability_token}"
91
+ )
92
+
93
+ # ── Serialization ─────────────────────────────────────────────────────
94
+
95
+ def to_bytes(self) -> bytes:
96
+ """Serialize to binary (52-byte header + payload).
97
+
98
+ The compact header drops the low 8 bytes of *conversation_id* and
99
+ reduces *in_reply_to* to a uint16 tag (0 when None).
100
+ """
101
+ # conversation_id → first 8 bytes of UUID (time_low + time_mid + time_hi)
102
+ conv_bytes = self.conversation_id.bytes[:8]
103
+
104
+ # in_reply_to → uint16 from first 2 bytes, 0 if None
105
+ reply_u16 = 0
106
+ if self.in_reply_to is not None:
107
+ reply_u16 = int.from_bytes(
108
+ self.in_reply_to.bytes[:2], byteorder="little"
109
+ )
110
+
111
+ header = _HEADER_STRUCT.pack(
112
+ self.sender.bytes,
113
+ self.receiver.bytes,
114
+ conv_bytes,
115
+ self.message_type,
116
+ self.priority,
117
+ self.trust_token,
118
+ self.capability_token,
119
+ reply_u16,
120
+ )
121
+ return header + self.payload
122
+
123
+ @classmethod
124
+ def from_bytes(cls, data: bytes) -> A2AMessage:
125
+ """Deserialize from binary.
126
+
127
+ Raises ``ValueError`` if the buffer is shorter than 52 bytes.
128
+ """
129
+ if len(data) < cls.HEADER_SIZE:
130
+ raise ValueError(
131
+ f"A2AMessage requires at least {cls.HEADER_SIZE} bytes, "
132
+ f"got {len(data)}"
133
+ )
134
+
135
+ (sender_b, receiver_b, conv_b, msg_type, prio,
136
+ trust_tok, cap_tok, reply_u16) = _HEADER_STRUCT.unpack_from(data, 0)
137
+
138
+ # Reconstruct full UUIDs from compact fields
139
+ sender = uuid.UUID(bytes=sender_b)
140
+ receiver = uuid.UUID(bytes=receiver_b)
141
+ conversation_id = uuid.UUID(bytes=conv_b + b"\x00" * 8)
142
+
143
+ # Reconstruct in_reply_to
144
+ in_reply_to = None
145
+ if reply_u16 != 0:
146
+ in_reply_to = uuid.UUID(
147
+ bytes=reply_u16.to_bytes(2, byteorder="little") + b"\x00" * 14
148
+ )
149
+
150
+ payload = data[cls.HEADER_SIZE:]
151
+
152
+ return cls(
153
+ sender=sender,
154
+ receiver=receiver,
155
+ conversation_id=conversation_id,
156
+ in_reply_to=in_reply_to,
157
+ message_type=msg_type,
158
+ priority=prio,
159
+ trust_token=trust_tok,
160
+ capability_token=cap_tok,
161
+ payload=payload,
162
+ )
163
+
164
+ def __repr__(self) -> str:
165
+ return (
166
+ f"A2AMessage(type=0x{self.message_type:02X}, "
167
+ f"sender={self.sender}, receiver={self.receiver}, "
168
+ f"conv={self.conversation_id}, "
169
+ f"priority={self.priority}, "
170
+ f"payload_len={len(self.payload)})"
171
+ )