htmlgraph 0.24.2__py3-none-any.whl → 0.26.1__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.
- htmlgraph/__init__.py +20 -1
- htmlgraph/agent_detection.py +26 -10
- htmlgraph/analytics/cross_session.py +4 -3
- htmlgraph/analytics/work_type.py +52 -16
- htmlgraph/analytics_index.py +51 -19
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/main.py +2263 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +812 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1020 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +509 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +163 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/builders/base.py +55 -1
- htmlgraph/builders/bug.py +17 -2
- htmlgraph/builders/chore.py +17 -2
- htmlgraph/builders/epic.py +17 -2
- htmlgraph/builders/feature.py +25 -2
- htmlgraph/builders/phase.py +17 -2
- htmlgraph/builders/spike.py +27 -2
- htmlgraph/builders/track.py +14 -0
- htmlgraph/cigs/__init__.py +4 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cli.py +1427 -401
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +2 -0
- htmlgraph/collections/base.py +21 -0
- htmlgraph/collections/session.py +189 -0
- htmlgraph/collections/spike.py +7 -1
- htmlgraph/collections/task_delegation.py +236 -0
- htmlgraph/collections/traces.py +482 -0
- htmlgraph/config.py +113 -0
- htmlgraph/converter.py +41 -0
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +3356 -492
- htmlgraph-0.24.2.data/data/htmlgraph/dashboard.html → htmlgraph/dashboard.html.backup +2246 -248
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1584 -0
- htmlgraph/deploy.py +26 -27
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +710 -0
- htmlgraph/docs/README.md +533 -0
- htmlgraph/docs/version_check.py +3 -1
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +2 -0
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +8 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +2 -2
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +318 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +496 -79
- htmlgraph/hooks/orchestrator.py +6 -4
- htmlgraph/hooks/orchestrator_reflector.py +4 -4
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/pretooluse.py +473 -6
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +637 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_stop.py +309 -0
- htmlgraph/hooks/task_enforcer.py +39 -0
- htmlgraph/hooks/validator.py +15 -11
- htmlgraph/models.py +111 -15
- htmlgraph/operations/fastapi_server.py +230 -0
- htmlgraph/orchestration/headless_spawner.py +344 -29
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/repo_hash.py +511 -0
- htmlgraph/sdk.py +348 -10
- htmlgraph/server.py +194 -0
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +131 -1
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/system_prompts.py +449 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +19 -0
- htmlgraph/validation.py +115 -0
- htmlgraph-0.26.1.data/data/htmlgraph/dashboard.html +7458 -0
- {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/METADATA +91 -64
- {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/RECORD +112 -46
- {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/WHEEL +0 -0
- {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Live Event Publisher for Real-Time WebSocket Streaming.
|
|
3
|
+
|
|
4
|
+
This module provides a centralized way to publish live events that will be
|
|
5
|
+
streamed to connected WebSocket clients in real-time. Events are stored in
|
|
6
|
+
a SQLite table and polled by the WebSocket handler.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from htmlgraph.orchestration.live_events import LiveEventPublisher
|
|
10
|
+
|
|
11
|
+
publisher = LiveEventPublisher()
|
|
12
|
+
publisher.spawner_start("gemini", "Analyze codebase", parent_event_id="evt-123")
|
|
13
|
+
publisher.spawner_phase("gemini", "executing", progress=50)
|
|
14
|
+
publisher.spawner_complete("gemini", success=True, duration=15.3, response="...")
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LiveEventPublisher:
|
|
28
|
+
"""
|
|
29
|
+
Publisher for live events that get streamed via WebSocket.
|
|
30
|
+
|
|
31
|
+
Events are written to the live_events table in SQLite and polled
|
|
32
|
+
by the dashboard WebSocket handler for real-time streaming.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, db_path: str | None = None):
|
|
36
|
+
"""
|
|
37
|
+
Initialize the live event publisher.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
db_path: Path to SQLite database. If None, uses default location.
|
|
41
|
+
"""
|
|
42
|
+
self._db_path = db_path
|
|
43
|
+
self._db: Any = None
|
|
44
|
+
|
|
45
|
+
def _get_db(self) -> Any:
|
|
46
|
+
"""Get or create database connection."""
|
|
47
|
+
if self._db is None:
|
|
48
|
+
try:
|
|
49
|
+
from htmlgraph.db.schema import HtmlGraphDB
|
|
50
|
+
|
|
51
|
+
if self._db_path:
|
|
52
|
+
self._db = HtmlGraphDB(self._db_path)
|
|
53
|
+
else:
|
|
54
|
+
# Use project database path from environment or cwd
|
|
55
|
+
project_root = os.getenv("HTMLGRAPH_PROJECT_ROOT", os.getcwd())
|
|
56
|
+
default_path = str(
|
|
57
|
+
Path(project_root) / ".htmlgraph" / "index.sqlite"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Check if database exists
|
|
61
|
+
if not Path(default_path).exists():
|
|
62
|
+
logger.debug(f"Database not found at {default_path}")
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
self._db = HtmlGraphDB(default_path)
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.warning(f"Failed to initialize database for live events: {e}")
|
|
68
|
+
return None
|
|
69
|
+
return self._db
|
|
70
|
+
|
|
71
|
+
def _get_session_id(self) -> str | None:
|
|
72
|
+
"""Get current session ID from environment."""
|
|
73
|
+
return os.getenv("HTMLGRAPH_PARENT_SESSION") or os.getenv("CLAUDE_SESSION_ID")
|
|
74
|
+
|
|
75
|
+
def publish(
|
|
76
|
+
self,
|
|
77
|
+
event_type: str,
|
|
78
|
+
event_data: dict[str, Any],
|
|
79
|
+
parent_event_id: str | None = None,
|
|
80
|
+
session_id: str | None = None,
|
|
81
|
+
spawner_type: str | None = None,
|
|
82
|
+
) -> int | None:
|
|
83
|
+
"""
|
|
84
|
+
Publish a live event for WebSocket streaming.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
event_type: Type of event (e.g., spawner_start, spawner_complete)
|
|
88
|
+
event_data: Event payload dictionary
|
|
89
|
+
parent_event_id: Parent event ID for hierarchical linking
|
|
90
|
+
session_id: Session this event belongs to
|
|
91
|
+
spawner_type: Spawner type if applicable (gemini, codex, copilot)
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Live event ID if successful, None otherwise
|
|
95
|
+
"""
|
|
96
|
+
db = self._get_db()
|
|
97
|
+
if db is None:
|
|
98
|
+
logger.debug("Database not available for live events")
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
# Add timestamp to event data if not present
|
|
102
|
+
if "timestamp" not in event_data:
|
|
103
|
+
event_data["timestamp"] = datetime.now(timezone.utc).isoformat()
|
|
104
|
+
|
|
105
|
+
# Use session from environment if not provided
|
|
106
|
+
if session_id is None:
|
|
107
|
+
session_id = self._get_session_id()
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
result: int | None = db.insert_live_event(
|
|
111
|
+
event_type=event_type,
|
|
112
|
+
event_data=event_data,
|
|
113
|
+
parent_event_id=parent_event_id,
|
|
114
|
+
session_id=session_id,
|
|
115
|
+
spawner_type=spawner_type,
|
|
116
|
+
)
|
|
117
|
+
return result
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.warning(f"Failed to publish live event: {e}")
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
def spawner_start(
|
|
123
|
+
self,
|
|
124
|
+
spawner_type: str,
|
|
125
|
+
prompt: str,
|
|
126
|
+
parent_event_id: str | None = None,
|
|
127
|
+
model: str | None = None,
|
|
128
|
+
session_id: str | None = None,
|
|
129
|
+
) -> int | None:
|
|
130
|
+
"""
|
|
131
|
+
Publish a spawner start event.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
spawner_type: Type of spawner (gemini, codex, copilot)
|
|
135
|
+
prompt: Task prompt being executed
|
|
136
|
+
parent_event_id: Parent delegation event ID
|
|
137
|
+
model: Model being used (optional)
|
|
138
|
+
session_id: Session ID (optional, auto-detected)
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Live event ID if successful
|
|
142
|
+
"""
|
|
143
|
+
event_data = {
|
|
144
|
+
"spawner_type": spawner_type,
|
|
145
|
+
"prompt_preview": prompt[:200] if prompt else "",
|
|
146
|
+
"prompt_length": len(prompt) if prompt else 0,
|
|
147
|
+
"status": "started",
|
|
148
|
+
"phase": "initializing",
|
|
149
|
+
}
|
|
150
|
+
if model:
|
|
151
|
+
event_data["model"] = model
|
|
152
|
+
|
|
153
|
+
return self.publish(
|
|
154
|
+
event_type="spawner_start",
|
|
155
|
+
event_data=event_data,
|
|
156
|
+
parent_event_id=parent_event_id,
|
|
157
|
+
session_id=session_id,
|
|
158
|
+
spawner_type=spawner_type,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def spawner_phase(
|
|
162
|
+
self,
|
|
163
|
+
spawner_type: str,
|
|
164
|
+
phase: str,
|
|
165
|
+
progress: int | None = None,
|
|
166
|
+
details: str | None = None,
|
|
167
|
+
parent_event_id: str | None = None,
|
|
168
|
+
session_id: str | None = None,
|
|
169
|
+
) -> int | None:
|
|
170
|
+
"""
|
|
171
|
+
Publish a spawner phase update event.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
spawner_type: Type of spawner (gemini, codex, copilot)
|
|
175
|
+
phase: Current phase (e.g., "executing", "processing", "streaming")
|
|
176
|
+
progress: Progress percentage (0-100) if applicable
|
|
177
|
+
details: Additional details about the phase
|
|
178
|
+
parent_event_id: Parent delegation event ID
|
|
179
|
+
session_id: Session ID (optional, auto-detected)
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Live event ID if successful
|
|
183
|
+
"""
|
|
184
|
+
event_data: dict[str, Any] = {
|
|
185
|
+
"spawner_type": spawner_type,
|
|
186
|
+
"phase": phase,
|
|
187
|
+
"status": "in_progress",
|
|
188
|
+
}
|
|
189
|
+
if progress is not None:
|
|
190
|
+
event_data["progress"] = progress
|
|
191
|
+
if details:
|
|
192
|
+
event_data["details"] = details[:200]
|
|
193
|
+
|
|
194
|
+
return self.publish(
|
|
195
|
+
event_type="spawner_phase",
|
|
196
|
+
event_data=event_data,
|
|
197
|
+
parent_event_id=parent_event_id,
|
|
198
|
+
session_id=session_id,
|
|
199
|
+
spawner_type=spawner_type,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
def spawner_complete(
|
|
203
|
+
self,
|
|
204
|
+
spawner_type: str,
|
|
205
|
+
success: bool,
|
|
206
|
+
duration_seconds: float | None = None,
|
|
207
|
+
response_preview: str | None = None,
|
|
208
|
+
tokens_used: int | None = None,
|
|
209
|
+
error: str | None = None,
|
|
210
|
+
parent_event_id: str | None = None,
|
|
211
|
+
session_id: str | None = None,
|
|
212
|
+
) -> int | None:
|
|
213
|
+
"""
|
|
214
|
+
Publish a spawner completion event.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
spawner_type: Type of spawner (gemini, codex, copilot)
|
|
218
|
+
success: Whether the spawner completed successfully
|
|
219
|
+
duration_seconds: Execution duration in seconds
|
|
220
|
+
response_preview: Preview of the response (first 200 chars)
|
|
221
|
+
tokens_used: Number of tokens used
|
|
222
|
+
error: Error message if failed
|
|
223
|
+
parent_event_id: Parent delegation event ID
|
|
224
|
+
session_id: Session ID (optional, auto-detected)
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Live event ID if successful
|
|
228
|
+
"""
|
|
229
|
+
event_data: dict[str, Any] = {
|
|
230
|
+
"spawner_type": spawner_type,
|
|
231
|
+
"success": success,
|
|
232
|
+
"status": "completed" if success else "failed",
|
|
233
|
+
"phase": "done",
|
|
234
|
+
}
|
|
235
|
+
if duration_seconds is not None:
|
|
236
|
+
event_data["duration_seconds"] = round(duration_seconds, 2)
|
|
237
|
+
if response_preview:
|
|
238
|
+
event_data["response_preview"] = response_preview[:200]
|
|
239
|
+
if tokens_used is not None:
|
|
240
|
+
event_data["tokens_used"] = tokens_used
|
|
241
|
+
if error:
|
|
242
|
+
event_data["error"] = error[:500]
|
|
243
|
+
|
|
244
|
+
return self.publish(
|
|
245
|
+
event_type="spawner_complete",
|
|
246
|
+
event_data=event_data,
|
|
247
|
+
parent_event_id=parent_event_id,
|
|
248
|
+
session_id=session_id,
|
|
249
|
+
spawner_type=spawner_type,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def spawner_tool_use(
|
|
253
|
+
self,
|
|
254
|
+
spawner_type: str,
|
|
255
|
+
tool_name: str,
|
|
256
|
+
tool_input: dict[str, Any] | None = None,
|
|
257
|
+
parent_event_id: str | None = None,
|
|
258
|
+
session_id: str | None = None,
|
|
259
|
+
) -> int | None:
|
|
260
|
+
"""
|
|
261
|
+
Publish a spawner tool use event (when spawned AI uses a tool).
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
spawner_type: Type of spawner (gemini, codex, copilot)
|
|
265
|
+
tool_name: Name of the tool being used
|
|
266
|
+
tool_input: Tool input parameters
|
|
267
|
+
parent_event_id: Parent delegation event ID
|
|
268
|
+
session_id: Session ID (optional, auto-detected)
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Live event ID if successful
|
|
272
|
+
"""
|
|
273
|
+
event_data: dict[str, Any] = {
|
|
274
|
+
"spawner_type": spawner_type,
|
|
275
|
+
"tool_name": tool_name,
|
|
276
|
+
"status": "tool_use",
|
|
277
|
+
"phase": "executing",
|
|
278
|
+
}
|
|
279
|
+
if tool_input:
|
|
280
|
+
# Truncate tool input for preview
|
|
281
|
+
input_str = json.dumps(tool_input)
|
|
282
|
+
event_data["tool_input_preview"] = input_str[:200]
|
|
283
|
+
|
|
284
|
+
return self.publish(
|
|
285
|
+
event_type="spawner_tool_use",
|
|
286
|
+
event_data=event_data,
|
|
287
|
+
parent_event_id=parent_event_id,
|
|
288
|
+
session_id=session_id,
|
|
289
|
+
spawner_type=spawner_type,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
def spawner_message(
|
|
293
|
+
self,
|
|
294
|
+
spawner_type: str,
|
|
295
|
+
message: str,
|
|
296
|
+
role: str = "assistant",
|
|
297
|
+
parent_event_id: str | None = None,
|
|
298
|
+
session_id: str | None = None,
|
|
299
|
+
) -> int | None:
|
|
300
|
+
"""
|
|
301
|
+
Publish a spawner message event (when spawned AI sends a message).
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
spawner_type: Type of spawner (gemini, codex, copilot)
|
|
305
|
+
message: Message content
|
|
306
|
+
role: Message role (assistant, user, system)
|
|
307
|
+
parent_event_id: Parent delegation event ID
|
|
308
|
+
session_id: Session ID (optional, auto-detected)
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Live event ID if successful
|
|
312
|
+
"""
|
|
313
|
+
event_data = {
|
|
314
|
+
"spawner_type": spawner_type,
|
|
315
|
+
"message_preview": message[:200] if message else "",
|
|
316
|
+
"message_length": len(message) if message else 0,
|
|
317
|
+
"role": role,
|
|
318
|
+
"status": "streaming",
|
|
319
|
+
"phase": "responding",
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return self.publish(
|
|
323
|
+
event_type="spawner_message",
|
|
324
|
+
event_data=event_data,
|
|
325
|
+
parent_event_id=parent_event_id,
|
|
326
|
+
session_id=session_id,
|
|
327
|
+
spawner_type=spawner_type,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# Global singleton instance for convenience
|
|
332
|
+
_publisher: LiveEventPublisher | None = None
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def get_publisher(db_path: str | None = None) -> LiveEventPublisher:
|
|
336
|
+
"""
|
|
337
|
+
Get the global LiveEventPublisher instance.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
db_path: Optional database path (only used on first call)
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
LiveEventPublisher instance
|
|
344
|
+
"""
|
|
345
|
+
global _publisher
|
|
346
|
+
if _publisher is None:
|
|
347
|
+
_publisher = LiveEventPublisher(db_path)
|
|
348
|
+
return _publisher
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def publish_live_event(
|
|
352
|
+
event_type: str,
|
|
353
|
+
event_data: dict[str, Any],
|
|
354
|
+
parent_event_id: str | None = None,
|
|
355
|
+
session_id: str | None = None,
|
|
356
|
+
spawner_type: str | None = None,
|
|
357
|
+
) -> int | None:
|
|
358
|
+
"""
|
|
359
|
+
Convenience function to publish a live event using the global publisher.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
event_type: Type of event
|
|
363
|
+
event_data: Event payload
|
|
364
|
+
parent_event_id: Parent event ID
|
|
365
|
+
session_id: Session ID
|
|
366
|
+
spawner_type: Spawner type
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Live event ID if successful
|
|
370
|
+
"""
|
|
371
|
+
return get_publisher().publish(
|
|
372
|
+
event_type=event_type,
|
|
373
|
+
event_data=event_data,
|
|
374
|
+
parent_event_id=parent_event_id,
|
|
375
|
+
session_id=session_id,
|
|
376
|
+
spawner_type=spawner_type,
|
|
377
|
+
)
|