GitHub Actions commited on
Commit
fa5b4a9
·
1 Parent(s): caa7fae

fix(chat): wire ChatService with bus in app.py so cross-node sends deliver

Browse files

The HF Space / UI entry point constructed ChatService without a bus=
reference, so _deliver_remote short-circuited to 'queued' before ever
attempting remote delivery. Pass bus=node.bus (matching node.py wiring)
so local->peer chat is delivered over the bus transport.

Verified live: local browser UI -> HF Space now reports 'delivered' and
the message lands in the Space chat log.

Add regression tests covering manual ChatService wiring + the no-bus
failure mode. Tidy stray blank lines in relay_client.

app.py CHANGED
@@ -378,7 +378,7 @@ def _build_node():
378
 
379
  # Marketplace, Chat, Files — now durably event-sourced where supported.
380
  node.bus.register_service(MarketplaceService(event_log=event_log, node_id=node.node_id))
381
- node.bus.register_service(ChatService(node.node_id, event_log=event_log))
382
  node.bus.register_service(FileService())
383
 
384
  return node
 
378
 
379
  # Marketplace, Chat, Files — now durably event-sourced where supported.
380
  node.bus.register_service(MarketplaceService(event_log=event_log, node_id=node.node_id))
381
+ node.bus.register_service(ChatService(node.node_id, event_log=event_log, bus=node.bus))
382
  node.bus.register_service(FileService())
383
 
384
  return node
hearthnet/transport/relay_client.py CHANGED
@@ -336,8 +336,6 @@ class RelayClient:
336
  self._bus.registry.update_from_peer_manifest(record, manifest)
337
 
338
 
339
-
340
-
341
  class RelayStrategy:
342
  """Adapts a :class:`RelayClient` to the bus ``DeliveryStrategy`` protocol."""
343
 
 
336
  self._bus.registry.update_from_peer_manifest(record, manifest)
337
 
338
 
 
 
339
  class RelayStrategy:
340
  """Adapts a :class:`RelayClient` to the bus ``DeliveryStrategy`` protocol."""
341
 
tests/test_chat_cross_node.py CHANGED
@@ -74,3 +74,44 @@ async def test_send_to_unknown_node_returns_queued(two_nodes):
74
  )
75
  status = r.get("output", {}).get("delivered")
76
  assert status == "queued", f"Expected 'queued' for unknown node, got {status!r}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  )
75
  status = r.get("output", {}).get("delivered")
76
  assert status == "queued", f"Expected 'queued' for unknown node, got {status!r}"
77
+
78
+
79
+ @pytest.mark.asyncio
80
+ async def test_manually_wired_chat_service_delivers():
81
+ """Regression: a ChatService registered manually (as app.py / the HF Space
82
+ entry point does) must receive a ``bus=`` reference, otherwise
83
+ ``_deliver_remote`` short-circuits to ``"queued"`` before attempting
84
+ delivery. Mirrors the app.py wiring to guard against that regression.
85
+ """
86
+ from hearthnet.node import HearthNode
87
+ from hearthnet.services.chat.service import ChatService
88
+
89
+ net = InMemoryTransport()
90
+ alice = HearthNode("node-alice", "Alice", "ed25519:test", transport=net)
91
+ # Wire chat exactly like app.py: explicit bus= argument is required.
92
+ alice.bus.register_service(ChatService(alice.node_id, bus=alice.bus))
93
+ net.register(alice.bus)
94
+
95
+ bob = HearthNode("node-bob", "Bob", "ed25519:test", transport=net)
96
+ bob.bus.register_service(ChatService(bob.node_id, bus=bob.bus))
97
+ net.register(bob.bus)
98
+
99
+ r = await alice.bus.call(
100
+ "chat.send", (1, 0), {"input": {"recipient": "node-bob", "body": "wired"}}
101
+ )
102
+ assert r.get("output", {}).get("delivered") == "delivered"
103
+
104
+
105
+ @pytest.mark.asyncio
106
+ async def test_chat_service_without_bus_cannot_deliver():
107
+ """A ChatService constructed without a bus reference can only queue —
108
+ documents the failure mode the app.py wiring fix prevents.
109
+ """
110
+ from hearthnet.services.chat.service import ChatService
111
+
112
+ svc = ChatService("node-alice") # no bus=
113
+ status = await svc._deliver_remote(
114
+ {"to": "node-bob", "from": "node-alice", "body": "x", "event_id": "e1"}
115
+ )
116
+ assert status == "queued"
117
+