@elizaos/python 2.0.0-alpha.10 → 2.0.0-alpha.26

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 (145) hide show
  1. package/elizaos/__init__.py +0 -1
  2. package/elizaos/advanced_capabilities/__init__.py +6 -41
  3. package/elizaos/advanced_capabilities/actions/__init__.py +1 -21
  4. package/elizaos/advanced_capabilities/actions/add_contact.py +21 -11
  5. package/elizaos/advanced_capabilities/actions/follow_room.py +28 -28
  6. package/elizaos/advanced_capabilities/actions/image_generation.py +13 -26
  7. package/elizaos/advanced_capabilities/actions/mute_room.py +13 -26
  8. package/elizaos/advanced_capabilities/actions/remove_contact.py +16 -2
  9. package/elizaos/advanced_capabilities/actions/roles.py +13 -27
  10. package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +70 -15
  11. package/elizaos/advanced_capabilities/actions/search_contacts.py +17 -3
  12. package/elizaos/advanced_capabilities/actions/send_message.py +183 -50
  13. package/elizaos/advanced_capabilities/actions/settings.py +16 -2
  14. package/elizaos/advanced_capabilities/actions/unfollow_room.py +13 -26
  15. package/elizaos/advanced_capabilities/actions/unmute_room.py +13 -26
  16. package/elizaos/advanced_capabilities/actions/update_contact.py +16 -2
  17. package/elizaos/advanced_capabilities/actions/update_entity.py +16 -2
  18. package/elizaos/advanced_capabilities/evaluators/__init__.py +2 -9
  19. package/elizaos/advanced_capabilities/evaluators/reflection.py +3 -132
  20. package/elizaos/advanced_capabilities/evaluators/relationship_extraction.py +5 -201
  21. package/elizaos/advanced_capabilities/providers/__init__.py +1 -12
  22. package/elizaos/advanced_capabilities/providers/knowledge.py +24 -3
  23. package/elizaos/advanced_capabilities/services/__init__.py +2 -9
  24. package/elizaos/advanced_memory/actions/reset_session.py +11 -0
  25. package/elizaos/advanced_memory/evaluators/reflection.py +134 -0
  26. package/elizaos/advanced_memory/evaluators/relationship_extraction.py +203 -0
  27. package/elizaos/advanced_memory/memory_service.py +15 -17
  28. package/elizaos/advanced_memory/test_advanced_memory.py +357 -0
  29. package/elizaos/advanced_planning/actions/schedule_follow_up.py +222 -0
  30. package/elizaos/advanced_planning/planning_service.py +26 -14
  31. package/elizaos/basic_capabilities/__init__.py +0 -2
  32. package/elizaos/basic_capabilities/providers/__init__.py +0 -3
  33. package/elizaos/basic_capabilities/providers/actions.py +118 -29
  34. package/elizaos/basic_capabilities/providers/agent_settings.py +64 -0
  35. package/elizaos/basic_capabilities/providers/character.py +19 -21
  36. package/elizaos/basic_capabilities/providers/contacts.py +79 -0
  37. package/elizaos/basic_capabilities/providers/current_time.py +7 -4
  38. package/elizaos/basic_capabilities/providers/facts.py +87 -0
  39. package/elizaos/basic_capabilities/providers/follow_ups.py +117 -0
  40. package/elizaos/basic_capabilities/providers/knowledge.py +97 -0
  41. package/elizaos/basic_capabilities/providers/relationships.py +107 -0
  42. package/elizaos/basic_capabilities/providers/roles.py +96 -0
  43. package/elizaos/basic_capabilities/providers/settings.py +56 -0
  44. package/elizaos/basic_capabilities/providers/time.py +7 -4
  45. package/elizaos/bootstrap/__init__.py +21 -2
  46. package/elizaos/bootstrap/actions/schedule_follow_up.py +65 -7
  47. package/elizaos/bootstrap/actions/send_message.py +162 -15
  48. package/elizaos/bootstrap/autonomy/__init__.py +5 -1
  49. package/elizaos/bootstrap/autonomy/action.py +161 -0
  50. package/elizaos/bootstrap/autonomy/evaluators.py +217 -0
  51. package/elizaos/bootstrap/autonomy/service.py +238 -28
  52. package/elizaos/bootstrap/plugin.py +7 -0
  53. package/elizaos/bootstrap/providers/actions.py +118 -27
  54. package/elizaos/bootstrap/providers/agent_settings.py +1 -0
  55. package/elizaos/bootstrap/providers/attachments.py +1 -0
  56. package/elizaos/bootstrap/providers/capabilities.py +1 -0
  57. package/elizaos/bootstrap/providers/character.py +1 -0
  58. package/elizaos/bootstrap/providers/choice.py +1 -0
  59. package/elizaos/bootstrap/providers/contacts.py +1 -0
  60. package/elizaos/bootstrap/providers/current_time.py +8 -2
  61. package/elizaos/bootstrap/providers/entities.py +1 -0
  62. package/elizaos/bootstrap/providers/evaluators.py +1 -0
  63. package/elizaos/bootstrap/providers/facts.py +1 -0
  64. package/elizaos/bootstrap/providers/follow_ups.py +1 -0
  65. package/elizaos/bootstrap/providers/knowledge.py +27 -3
  66. package/elizaos/bootstrap/providers/providers_list.py +1 -0
  67. package/elizaos/bootstrap/providers/relationships.py +1 -0
  68. package/elizaos/bootstrap/providers/roles.py +1 -0
  69. package/elizaos/bootstrap/providers/settings.py +1 -0
  70. package/elizaos/bootstrap/providers/time.py +8 -4
  71. package/elizaos/bootstrap/providers/world.py +1 -0
  72. package/elizaos/bootstrap/services/embedding.py +156 -1
  73. package/elizaos/deterministic.py +193 -0
  74. package/elizaos/generated/__init__.py +1 -0
  75. package/elizaos/generated/action_docs.py +3181 -0
  76. package/elizaos/generated/spec_helpers.py +175 -0
  77. package/elizaos/media/mime.py +2 -2
  78. package/elizaos/media/search.py +23 -23
  79. package/elizaos/runtime.py +215 -57
  80. package/elizaos/services/message_service.py +175 -29
  81. package/elizaos/types/components.py +2 -2
  82. package/elizaos/types/generated/__init__.py +12 -0
  83. package/elizaos/types/generated/eliza/v1/agent_pb2.py +63 -0
  84. package/elizaos/types/generated/eliza/v1/agent_pb2.pyi +159 -0
  85. package/elizaos/types/generated/eliza/v1/components_pb2.py +65 -0
  86. package/elizaos/types/generated/eliza/v1/components_pb2.pyi +160 -0
  87. package/elizaos/types/generated/eliza/v1/database_pb2.py +78 -0
  88. package/elizaos/types/generated/eliza/v1/database_pb2.pyi +305 -0
  89. package/elizaos/types/generated/eliza/v1/environment_pb2.py +58 -0
  90. package/elizaos/types/generated/eliza/v1/environment_pb2.pyi +135 -0
  91. package/elizaos/types/generated/eliza/v1/events_pb2.py +82 -0
  92. package/elizaos/types/generated/eliza/v1/events_pb2.pyi +322 -0
  93. package/elizaos/types/generated/eliza/v1/ipc_pb2.py +113 -0
  94. package/elizaos/types/generated/eliza/v1/ipc_pb2.pyi +367 -0
  95. package/elizaos/types/generated/eliza/v1/knowledge_pb2.py +41 -0
  96. package/elizaos/types/generated/eliza/v1/knowledge_pb2.pyi +26 -0
  97. package/elizaos/types/generated/eliza/v1/memory_pb2.py +55 -0
  98. package/elizaos/types/generated/eliza/v1/memory_pb2.pyi +111 -0
  99. package/elizaos/types/generated/eliza/v1/message_service_pb2.py +48 -0
  100. package/elizaos/types/generated/eliza/v1/message_service_pb2.pyi +69 -0
  101. package/elizaos/types/generated/eliza/v1/messaging_pb2.py +51 -0
  102. package/elizaos/types/generated/eliza/v1/messaging_pb2.pyi +97 -0
  103. package/elizaos/types/generated/eliza/v1/model_pb2.py +84 -0
  104. package/elizaos/types/generated/eliza/v1/model_pb2.pyi +280 -0
  105. package/elizaos/types/generated/eliza/v1/payment_pb2.py +44 -0
  106. package/elizaos/types/generated/eliza/v1/payment_pb2.pyi +70 -0
  107. package/elizaos/types/generated/eliza/v1/plugin_pb2.py +68 -0
  108. package/elizaos/types/generated/eliza/v1/plugin_pb2.pyi +145 -0
  109. package/elizaos/types/generated/eliza/v1/primitives_pb2.py +48 -0
  110. package/elizaos/types/generated/eliza/v1/primitives_pb2.pyi +92 -0
  111. package/elizaos/types/generated/eliza/v1/prompts_pb2.py +52 -0
  112. package/elizaos/types/generated/eliza/v1/prompts_pb2.pyi +74 -0
  113. package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.py +211 -0
  114. package/elizaos/types/generated/eliza/v1/service_interfaces_pb2.pyi +1296 -0
  115. package/elizaos/types/generated/eliza/v1/service_pb2.py +42 -0
  116. package/elizaos/types/generated/eliza/v1/service_pb2.pyi +69 -0
  117. package/elizaos/types/generated/eliza/v1/settings_pb2.py +58 -0
  118. package/elizaos/types/generated/eliza/v1/settings_pb2.pyi +85 -0
  119. package/elizaos/types/generated/eliza/v1/state_pb2.py +60 -0
  120. package/elizaos/types/generated/eliza/v1/state_pb2.pyi +114 -0
  121. package/elizaos/types/generated/eliza/v1/task_pb2.py +42 -0
  122. package/elizaos/types/generated/eliza/v1/task_pb2.pyi +58 -0
  123. package/elizaos/types/generated/eliza/v1/tee_pb2.py +52 -0
  124. package/elizaos/types/generated/eliza/v1/tee_pb2.pyi +90 -0
  125. package/elizaos/types/generated/eliza/v1/testing_pb2.py +39 -0
  126. package/elizaos/types/generated/eliza/v1/testing_pb2.pyi +23 -0
  127. package/elizaos/types/model.py +30 -0
  128. package/elizaos/types/runtime.py +6 -2
  129. package/elizaos/utils/validation.py +76 -0
  130. package/package.json +3 -2
  131. package/tests/test_action_parameters.py +2 -3
  132. package/tests/test_actions_provider_examples.py +58 -1
  133. package/tests/test_advanced_memory_behavior.py +0 -2
  134. package/tests/test_advanced_memory_flag.py +0 -2
  135. package/tests/test_advanced_planning_behavior.py +11 -5
  136. package/tests/test_async_embedding.py +124 -0
  137. package/tests/test_autonomy.py +24 -3
  138. package/tests/test_runtime.py +8 -17
  139. package/tests/test_schedule_follow_up_action.py +260 -0
  140. package/tests/test_send_message_action_targets.py +114 -0
  141. package/tests/test_settings_crypto.py +0 -2
  142. package/tests/test_validation.py +141 -0
  143. package/tests/verify_memory_architecture.py +192 -0
  144. package/uv.lock +1565 -0
  145. package/elizaos/basic_capabilities/providers/capabilities.py +0 -62
@@ -0,0 +1,141 @@
1
+ import time
2
+
3
+ from elizaos.types.memory import Memory
4
+ from elizaos.types.primitives import Content
5
+ from elizaos.utils.validation import validate_action_keywords, validate_action_regex
6
+
7
+
8
+ def create_mock_memory(text: str, id: str = "1") -> Memory:
9
+ return Memory(
10
+ id=id,
11
+ entity_id="user1",
12
+ room_id="room1",
13
+ agent_id="agent1",
14
+ content=Content(text=text),
15
+ created_at=int(time.time() * 1000),
16
+ )
17
+
18
+
19
+ def test_validate_action_keywords():
20
+ mock_message = Memory(
21
+ id="123",
22
+ entity_id="user1",
23
+ room_id="room1",
24
+ agent_id="agent1",
25
+ content=Content(text="Hello world"),
26
+ created_at=int(time.time() * 1000),
27
+ )
28
+
29
+ mock_recent_messages = [
30
+ Memory(
31
+ id="1",
32
+ entity_id="user1",
33
+ room_id="room1",
34
+ agent_id="agent1",
35
+ content=Content(text="Previous message 1"),
36
+ created_at=0,
37
+ ),
38
+ Memory(
39
+ id="2",
40
+ entity_id="user1",
41
+ room_id="room1",
42
+ agent_id="agent1",
43
+ content=Content(text="Previous message 2"),
44
+ created_at=0,
45
+ ),
46
+ Memory(
47
+ id="3",
48
+ entity_id="user1",
49
+ room_id="room1",
50
+ agent_id="agent1",
51
+ content=Content(text="Crypto is cool"),
52
+ created_at=0,
53
+ ),
54
+ Memory(
55
+ id="4",
56
+ entity_id="user1",
57
+ room_id="room1",
58
+ agent_id="agent1",
59
+ content=Content(text="Another message"),
60
+ created_at=0,
61
+ ),
62
+ Memory(
63
+ id="5",
64
+ entity_id="user1",
65
+ room_id="room1",
66
+ agent_id="agent1",
67
+ content=Content(text="Last one"),
68
+ created_at=0,
69
+ ),
70
+ ]
71
+
72
+ # 1. Keyword in current message
73
+ msg = create_mock_memory("I want to transfer sol", "124")
74
+ assert validate_action_keywords(msg, [], ["transfer"])
75
+
76
+ # 2. Keyword in recent messages
77
+ assert validate_action_keywords(mock_message, mock_recent_messages, ["crypto"])
78
+
79
+ # 3. Keyword not found
80
+ assert not validate_action_keywords(mock_message, mock_recent_messages, ["banana"])
81
+
82
+ # 4. Case insensitive
83
+ msg_upper = create_mock_memory("I want to TRANSFER sol", "125")
84
+ assert validate_action_keywords(msg_upper, [], ["transfer"])
85
+
86
+ # 5. Empty keywords list
87
+ assert not validate_action_keywords(mock_message, mock_recent_messages, [])
88
+
89
+ # 6. Partial match
90
+ msg_partial = Memory(
91
+ id="126",
92
+ entity_id="user1",
93
+ room_id="room1",
94
+ agent_id="agent1",
95
+ content=Content(text="cryptography"),
96
+ created_at=0,
97
+ )
98
+ assert validate_action_keywords(msg_partial, [], ["crypto"])
99
+
100
+
101
+ def test_validate_action_regex():
102
+ mock_message = create_mock_memory("Hello world", "123")
103
+ mock_recent_messages = [
104
+ create_mock_memory("Previous message 1", "1"),
105
+ create_mock_memory("Previous message 2", "2"),
106
+ create_mock_memory("Crypto is cool", "3"),
107
+ create_mock_memory("Another message", "4"),
108
+ create_mock_memory("Last one", "5"),
109
+ ]
110
+
111
+ # Regex in current message
112
+ msg = create_mock_memory("Transfer 100 SOL")
113
+ # Default re.search is case-sensitive
114
+ assert not validate_action_regex(msg, [], r"transfer \d+ sol")
115
+ # Use inline flag for case-insensitive
116
+ assert validate_action_regex(msg, [], r"(?i)transfer \d+ sol")
117
+
118
+ # Regex in recent messages
119
+ assert validate_action_regex(mock_message, mock_recent_messages, r"(?i)crypto")
120
+
121
+ # No match
122
+ assert not validate_action_regex(mock_message, mock_recent_messages, r"banana")
123
+
124
+ # Complex regex
125
+ msg = create_mock_memory("user@example.com")
126
+ assert validate_action_regex(msg, [], r"^[\w\.-]+@([\w-]+\.)+[\w-]{2,4}$") # Empty pattern
127
+ assert not validate_action_regex(mock_message, mock_recent_messages, "")
128
+
129
+ # Unicode characters
130
+ msg = create_mock_memory("Transfer 100 €")
131
+ assert not validate_action_regex(msg, [], r"transfer \d+ €") # case sensitive
132
+ assert validate_action_regex(msg, [], r"(?i)transfer \d+ €")
133
+
134
+ # Special characters
135
+ msg = create_mock_memory("Hello (world) [ok]")
136
+ assert validate_action_regex(msg, [], r"\(world\)")
137
+
138
+ # Long inputs (basic DoS check)
139
+ long_text = "a" * 10000 + "transfer"
140
+ msg = create_mock_memory(long_text)
141
+ assert validate_action_regex(msg, [], r"transfer")
@@ -0,0 +1,192 @@
1
+ import asyncio
2
+ import math
3
+ import unittest
4
+ import uuid
5
+ from unittest.mock import AsyncMock, MagicMock
6
+
7
+ from elizaos.bootstrap.services.embedding import EmbeddingService
8
+ from elizaos.types import ModelType
9
+ from elizaos.types.events import EventType
10
+ from elizaos.types.memory import Memory
11
+ from elizaos.types.primitives import Content
12
+
13
+ # Mock vector for "hello world" - simple 384 dim vector
14
+ MOCK_VECTOR_HELLO = [0.1] * 384
15
+ # Mock vector for something else - orthogonal or different
16
+ MOCK_VECTOR_OTHER = [-0.1] * 384
17
+
18
+
19
+ class MockRuntime(MagicMock):
20
+ def __init__(self, *args, **kwargs):
21
+ super().__init__(*args, **kwargs)
22
+ self.agent_id = uuid.uuid4()
23
+ self.logger = MagicMock()
24
+ self.events = {}
25
+ self._adapter = AsyncMock()
26
+ self._models = {}
27
+
28
+ # Setup model mock
29
+ async def use_model_side_effect(model_type, **kwargs):
30
+ if model_type == ModelType.TEXT_EMBEDDING:
31
+ text = kwargs.get("text", "")
32
+ if "hello" in text.lower():
33
+ return MOCK_VECTOR_HELLO
34
+ return MOCK_VECTOR_OTHER
35
+ if model_type == ModelType.TEXT_SMALL:
36
+ return "intent"
37
+ return None
38
+
39
+ self.use_model = AsyncMock(side_effect=use_model_side_effect)
40
+
41
+ def register_event(self, event, handler):
42
+ if event not in self.events:
43
+ self.events[event] = []
44
+ self.events[event].append(handler)
45
+
46
+ async def emit_event(self, event, payload):
47
+ handlers = self.events.get(event, [])
48
+ for handler in handlers:
49
+ if asyncio.iscoroutinefunction(handler):
50
+ await handler(payload)
51
+ else:
52
+ handler(payload)
53
+
54
+
55
+ def dot_product(v1: list[float], v2: list[float]) -> float:
56
+ return sum(x * y for x, y in zip(v1, v2, strict=False))
57
+
58
+
59
+ def magnitude(v: list[float]) -> float:
60
+ return math.sqrt(sum(x * x for x in v))
61
+
62
+
63
+ def cosine_similarity(v1: list[float], v2: list[float]) -> float:
64
+ m1 = magnitude(v1)
65
+ m2 = magnitude(v2)
66
+ if m1 == 0 or m2 == 0:
67
+ return 0.0
68
+ return dot_product(v1, v2) / (m1 * m2)
69
+
70
+
71
+ class VerifyMemoryArchitecture(unittest.IsolatedAsyncioTestCase):
72
+ async def test_end_to_end_memory_flow(self):
73
+ print("\n=== Starting Architectural Verification ===")
74
+
75
+ # 1. Setup
76
+ runtime = MockRuntime()
77
+ service = await EmbeddingService.start(runtime)
78
+
79
+ # --- TEST CASE 1: Short Message (Direct Embedding) ---
80
+ print("\n[Test 1] Short Message (< 20 chars) -> Direct Embedding")
81
+
82
+ short_id = str(uuid.uuid4())
83
+ short_memory = Memory(
84
+ id=short_id,
85
+ content=Content(text="Hello World"), # < 20 chars
86
+ room_id=str(uuid.uuid4()),
87
+ entity_id=str(uuid.uuid4()),
88
+ agent_id=str(runtime.agent_id),
89
+ )
90
+
91
+ # Reset Update Memory Mock
92
+ runtime._adapter.update_memory.reset_mock()
93
+
94
+ # Trigger
95
+ from types import SimpleNamespace
96
+
97
+ payload = SimpleNamespace(extra={"memory": short_memory})
98
+ await self._run_pipeline(runtime, payload)
99
+
100
+ # Verify
101
+ runtime._adapter.update_memory.assert_called_once()
102
+ stored_short = runtime._adapter.update_memory.call_args[0][0]
103
+
104
+ # "Hello World" contains "hello" -> MOCK_VECTOR_HELLO
105
+ sim = cosine_similarity(list(stored_short.embedding), MOCK_VECTOR_HELLO)
106
+ self.assertAlmostEqual(
107
+ sim, 1.0, places=4, msg="Short message should use direct embedding (Hello)"
108
+ )
109
+ print(f" -> Verified: Short message embedding matches content (sim={sim:.4f})")
110
+
111
+ # --- TEST CASE 2: Long Message (Intent Embedding) ---
112
+ print("\n[Test 2] Long Message (> 20 chars) -> Intent Embedding")
113
+
114
+ long_id = str(uuid.uuid4())
115
+ # "Hello World" repeated to be long, but also contains "hello"
116
+ # However, the logic generates INTENT.
117
+ # Mock returns "intent" as intent text.
118
+ # "intent" does NOT contain "hello", so mock returns MOCK_VECTOR_OTHER.
119
+ long_memory = Memory(
120
+ id=long_id,
121
+ content=Content(text="Hello World " * 5),
122
+ room_id=str(uuid.uuid4()),
123
+ entity_id=str(uuid.uuid4()),
124
+ agent_id=str(runtime.agent_id),
125
+ )
126
+
127
+ runtime._adapter.update_memory.reset_mock()
128
+
129
+ payload_long = SimpleNamespace(extra={"memory": long_memory})
130
+ await self._run_pipeline(runtime, payload_long)
131
+
132
+ runtime._adapter.update_memory.assert_called_once()
133
+ stored_long = runtime._adapter.update_memory.call_args[0][0]
134
+
135
+ # Expect MOCK_VECTOR_OTHER because embedding was on "intent"
136
+ sim_intent = cosine_similarity(list(stored_long.embedding), MOCK_VECTOR_OTHER)
137
+ self.assertAlmostEqual(
138
+ sim_intent, 1.0, places=4, msg="Long message should use intent embedding"
139
+ )
140
+
141
+ # Verify metadata
142
+ self.assertEqual(stored_long.metadata.custom.custom_data["intent"], "intent")
143
+ print(f" -> Verified: Long message uses intent embedding (sim={sim_intent:.4f})")
144
+ print(" -> Verified: Intent metadata stored")
145
+
146
+ # 4. Verify Retrieval & Similarity
147
+ print("\n[3] Verifying Retrieval & Similarity logic...")
148
+ # "Hello there" -> MOCK_VECTOR_HELLO
149
+ # "General Kenobi" -> MOCK_VECTOR_OTHER
150
+ score = await service.similarity("Hello there", "General Kenobi")
151
+
152
+ # Expected: dot(HELLO, OTHER)
153
+ # 384 * (0.1 * -0.1) = 384 * -0.01 = -3.84
154
+ # Mag(HELLO) = sqrt(384 * 0.01) = sqrt(3.84) ~= 1.9596
155
+ # Mag(OTHER) = sqrt(384 * 0.01) = sqrt(3.84) ~= 1.9596
156
+ # Cos = -3.84 / (1.9596 * 1.9596) = -3.84 / 3.84 = -1.0
157
+ expected_sim = cosine_similarity(MOCK_VECTOR_HELLO, MOCK_VECTOR_OTHER)
158
+ self.assertAlmostEqual(score, expected_sim, places=4)
159
+ print(f" -> Similarity calculation verified: {score:.4f} (expected {expected_sim:.4f})")
160
+
161
+ await service.stop()
162
+ print("=== Verification Complete ===")
163
+
164
+ async def _run_pipeline(self, runtime, payload):
165
+ event_name = EventType.Name(EventType.EVENT_TYPE_EMBEDDING_GENERATION_REQUESTED)
166
+ completion_future = asyncio.Future()
167
+
168
+ async def on_complete(p):
169
+ if not completion_future.done():
170
+ completion_future.set_result(p)
171
+
172
+ # We need to register/unregister to avoid duplicate calls if running multiple times
173
+ # But MockRuntime implementation appends.
174
+ # For simplicity, just append and ensure we trigger the right future?
175
+ # A new future is needed for each run.
176
+ # Let's clear mocks events for clean slate or just handle it.
177
+ # We can just register a new one.
178
+
179
+ runtime.register_event(
180
+ EventType.Name(EventType.EVENT_TYPE_EMBEDDING_GENERATION_COMPLETED), on_complete
181
+ )
182
+
183
+ await runtime.emit_event(event_name, payload)
184
+
185
+ try:
186
+ await asyncio.wait_for(completion_future, timeout=2.0)
187
+ except TimeoutError:
188
+ self.fail("Async pipeline timed out")
189
+
190
+
191
+ if __name__ == "__main__":
192
+ unittest.main()