@agentunion/kite 1.2.0 → 1.3.1
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.
- package/CHANGELOG.md +208 -0
- package/README.md +48 -0
- package/cli.js +1 -1
- package/extensions/agents/assistant/entry.py +30 -81
- package/extensions/agents/assistant/module.md +1 -1
- package/extensions/agents/assistant/server.py +83 -122
- package/extensions/channels/acp_channel/entry.py +30 -81
- package/extensions/channels/acp_channel/module.md +1 -1
- package/extensions/channels/acp_channel/server.py +83 -122
- package/extensions/event_hub_bench/entry.py +81 -121
- package/extensions/services/backup/entry.py +213 -85
- package/extensions/services/model_service/entry.py +213 -85
- package/extensions/services/watchdog/entry.py +513 -460
- package/extensions/services/watchdog/monitor.py +55 -69
- package/extensions/services/web/entry.py +11 -108
- package/extensions/services/web/server.py +120 -77
- package/{core/registry → kernel}/entry.py +65 -37
- package/{core/event_hub/hub.py → kernel/event_hub.py} +61 -81
- package/kernel/module.md +33 -0
- package/{core/registry/store.py → kernel/registry_store.py} +13 -4
- package/kernel/rpc_router.py +388 -0
- package/kernel/server.py +267 -0
- package/launcher/__init__.py +10 -0
- package/launcher/__main__.py +6 -0
- package/launcher/count_lines.py +258 -0
- package/{core/launcher → launcher}/entry.py +693 -767
- package/launcher/logging_setup.py +289 -0
- package/{core/launcher → launcher}/module_scanner.py +11 -6
- package/main.py +11 -350
- package/package.json +6 -9
- package/__init__.py +0 -1
- package/__main__.py +0 -15
- package/core/event_hub/BENCHMARK.md +0 -94
- package/core/event_hub/__init__.py +0 -0
- package/core/event_hub/bench.py +0 -459
- package/core/event_hub/bench_extreme.py +0 -308
- package/core/event_hub/bench_perf.py +0 -350
- package/core/event_hub/entry.py +0 -436
- package/core/event_hub/module.md +0 -20
- package/core/event_hub/server.py +0 -269
- package/core/kite_log.py +0 -241
- package/core/launcher/__init__.py +0 -0
- package/core/registry/__init__.py +0 -0
- package/core/registry/module.md +0 -30
- package/core/registry/server.py +0 -339
- package/extensions/services/backup/server.py +0 -244
- package/extensions/services/model_service/server.py +0 -236
- package/extensions/services/watchdog/server.py +0 -229
- /package/{core → kernel}/__init__.py +0 -0
- /package/{core/event_hub → kernel}/dedup.py +0 -0
- /package/{core/event_hub → kernel}/router.py +0 -0
- /package/{core/launcher → launcher}/module.md +0 -0
- /package/{core/launcher → launcher}/process_manager.py +0 -0
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Assistant
|
|
3
|
-
|
|
4
|
-
Connects to Event Hub via WebSocket for event publishing and subscription.
|
|
5
|
-
Sends periodic heartbeat to Registry and test events to Event Hub.
|
|
2
|
+
Assistant WebSocket client.
|
|
3
|
+
Connects to Kernel via WebSocket JSON-RPC 2.0 for event publishing and subscription.
|
|
6
4
|
"""
|
|
7
5
|
|
|
8
6
|
import asyncio
|
|
@@ -11,127 +9,101 @@ import time
|
|
|
11
9
|
import uuid
|
|
12
10
|
from datetime import datetime, timezone
|
|
13
11
|
|
|
14
|
-
import httpx
|
|
15
12
|
import websockets
|
|
16
|
-
from fastapi import FastAPI
|
|
17
13
|
|
|
18
14
|
|
|
19
15
|
class AssistantServer:
|
|
20
16
|
|
|
21
|
-
def __init__(self, token: str = "",
|
|
22
|
-
event_hub_ws: str = "", boot_t0: float = 0):
|
|
17
|
+
def __init__(self, token: str = "", kernel_port: int = 0, boot_t0: float = 0):
|
|
23
18
|
self.token = token
|
|
24
|
-
self.
|
|
25
|
-
self.event_hub_ws = event_hub_ws
|
|
19
|
+
self.kernel_port = kernel_port
|
|
26
20
|
self.boot_t0 = boot_t0
|
|
27
21
|
self._ws_task: asyncio.Task | None = None
|
|
28
|
-
self._heartbeat_task: asyncio.Task | None = None
|
|
29
22
|
self._test_task: asyncio.Task | None = None
|
|
30
23
|
self._ws: object | None = None
|
|
31
24
|
self._ready_sent = False
|
|
32
25
|
self._shutting_down = False
|
|
33
|
-
self._uvicorn_server = None # set by entry.py for graceful shutdown
|
|
34
26
|
self._start_time = time.time()
|
|
35
|
-
self.app = self._create_app()
|
|
36
|
-
|
|
37
|
-
def _create_app(self) -> FastAPI:
|
|
38
|
-
app = FastAPI(title="Kite Assistant", docs_url=None, redoc_url=None)
|
|
39
|
-
server = self
|
|
40
|
-
|
|
41
|
-
@app.on_event("startup")
|
|
42
|
-
async def _startup():
|
|
43
|
-
server._heartbeat_task = asyncio.create_task(server._heartbeat_loop())
|
|
44
|
-
if server.event_hub_ws:
|
|
45
|
-
server._ws_task = asyncio.create_task(server._ws_loop())
|
|
46
|
-
server._test_task = asyncio.create_task(server._test_event_loop())
|
|
47
|
-
|
|
48
|
-
@app.on_event("shutdown")
|
|
49
|
-
async def _shutdown():
|
|
50
|
-
if server._heartbeat_task:
|
|
51
|
-
server._heartbeat_task.cancel()
|
|
52
|
-
if server._ws_task:
|
|
53
|
-
server._ws_task.cancel()
|
|
54
|
-
if server._test_task:
|
|
55
|
-
server._test_task.cancel()
|
|
56
|
-
if server._ws:
|
|
57
|
-
await server._ws.close()
|
|
58
|
-
print("[assistant] Shutdown complete")
|
|
59
|
-
|
|
60
|
-
@app.get("/health")
|
|
61
|
-
async def health():
|
|
62
|
-
return {
|
|
63
|
-
"status": "healthy",
|
|
64
|
-
"details": {
|
|
65
|
-
"event_hub_connected": server._ws is not None,
|
|
66
|
-
"uptime_seconds": round(time.time() - server._start_time),
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
27
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
28
|
+
async def run(self):
|
|
29
|
+
"""Main entry point: start WebSocket loop and test event loop."""
|
|
30
|
+
if self.kernel_port:
|
|
31
|
+
self._ws_task = asyncio.create_task(self._ws_loop())
|
|
32
|
+
self._test_task = asyncio.create_task(self._test_event_loop())
|
|
33
|
+
|
|
34
|
+
# Wait for tasks to complete
|
|
35
|
+
tasks = [t for t in [self._ws_task, self._test_task] if t]
|
|
36
|
+
if tasks:
|
|
37
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
78
38
|
|
|
79
|
-
|
|
39
|
+
print("[assistant] Shutdown complete")
|
|
80
40
|
|
|
81
|
-
# ──
|
|
41
|
+
# ── Kernel WebSocket client ──
|
|
82
42
|
|
|
83
43
|
async def _ws_loop(self):
|
|
84
|
-
"""Connect to
|
|
85
|
-
retry_delay = 0.5
|
|
86
|
-
max_delay = 30
|
|
44
|
+
"""Connect to Kernel, subscribe, register, and listen. Reconnect on failure."""
|
|
45
|
+
retry_delay = 0.5
|
|
46
|
+
max_delay = 30
|
|
87
47
|
while not self._shutting_down:
|
|
88
48
|
try:
|
|
89
49
|
await self._ws_connect()
|
|
90
50
|
except asyncio.CancelledError:
|
|
91
51
|
return
|
|
92
|
-
retry_delay = 0.5 # reset on successful connection
|
|
93
52
|
except Exception as e:
|
|
94
|
-
print(f"[assistant]
|
|
53
|
+
print(f"[assistant] Kernel connection error: {e}, retrying in {retry_delay:.1f}s")
|
|
95
54
|
self._ws = None
|
|
96
55
|
if self._shutting_down:
|
|
97
56
|
return
|
|
98
57
|
await asyncio.sleep(retry_delay)
|
|
99
|
-
retry_delay = min(retry_delay * 2, max_delay)
|
|
58
|
+
retry_delay = min(retry_delay * 2, max_delay)
|
|
100
59
|
|
|
101
60
|
async def _ws_connect(self):
|
|
102
|
-
"""Single WebSocket session: connect, subscribe, receive loop."""
|
|
103
|
-
url = f"{self.
|
|
104
|
-
print(f"[assistant]
|
|
61
|
+
"""Single WebSocket session: connect, subscribe, register, ready, receive loop."""
|
|
62
|
+
url = f"ws://127.0.0.1:{self.kernel_port}/ws?token={self.token}&id=assistant"
|
|
63
|
+
print(f"[assistant] Connecting to Kernel (port {self.kernel_port})")
|
|
105
64
|
async with websockets.connect(url, open_timeout=3, ping_interval=None, ping_timeout=None, close_timeout=10) as ws:
|
|
106
65
|
self._ws = ws
|
|
107
66
|
elapsed = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
|
|
108
67
|
elapsed_str = f" ({elapsed:.1f}s)" if elapsed else ""
|
|
109
|
-
print(f"[assistant] Connected to
|
|
68
|
+
print(f"[assistant] Connected to Kernel{elapsed_str}")
|
|
110
69
|
|
|
111
|
-
# Subscribe to
|
|
112
|
-
await
|
|
113
|
-
"type": "subscribe",
|
|
70
|
+
# Step 1: Subscribe to events (先订阅)
|
|
71
|
+
await self._rpc_call(ws, "event.subscribe", {
|
|
114
72
|
"events": ["module.started", "module.stopped", "module.shutdown"],
|
|
115
|
-
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
# Step 2: Register to Kernel (再注册)
|
|
76
|
+
await self._rpc_call(ws, "registry.register", {
|
|
77
|
+
"module_id": "assistant",
|
|
78
|
+
"module_type": "agent",
|
|
79
|
+
"name": "Assistant",
|
|
80
|
+
"events_publish": {
|
|
81
|
+
"assistant.test": {},
|
|
82
|
+
},
|
|
83
|
+
"events_subscribe": [
|
|
84
|
+
"module.started",
|
|
85
|
+
"module.stopped",
|
|
86
|
+
"module.shutdown",
|
|
87
|
+
],
|
|
88
|
+
})
|
|
116
89
|
|
|
117
|
-
#
|
|
90
|
+
# Step 3: Publish module.ready (once)
|
|
118
91
|
if not self._ready_sent:
|
|
119
|
-
|
|
120
|
-
"type": "event",
|
|
92
|
+
await self._rpc_call(ws, "event.publish", {
|
|
121
93
|
"event_id": str(uuid.uuid4()),
|
|
122
94
|
"event": "module.ready",
|
|
123
|
-
"source": "assistant",
|
|
124
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
125
95
|
"data": {
|
|
126
96
|
"module_id": "assistant",
|
|
127
97
|
"graceful_shutdown": True,
|
|
128
98
|
},
|
|
129
|
-
}
|
|
130
|
-
await ws.send(json.dumps(ready_msg))
|
|
99
|
+
})
|
|
131
100
|
self._ready_sent = True
|
|
132
101
|
elapsed = time.monotonic() - self.boot_t0 if self.boot_t0 else 0
|
|
133
102
|
elapsed_str = f" ({elapsed:.1f}s)" if elapsed else ""
|
|
134
|
-
print(f"[assistant] module.ready
|
|
103
|
+
print(f"[assistant] module.ready published{elapsed_str}")
|
|
104
|
+
|
|
105
|
+
# Reset retry delay on successful connection
|
|
106
|
+
retry_delay = 0.5
|
|
135
107
|
|
|
136
108
|
# Receive loop
|
|
137
109
|
async for raw in ws:
|
|
@@ -141,18 +113,22 @@ class AssistantServer:
|
|
|
141
113
|
continue
|
|
142
114
|
|
|
143
115
|
try:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
116
|
+
has_method = "method" in msg
|
|
117
|
+
has_id = "id" in msg
|
|
118
|
+
|
|
119
|
+
if has_method and not has_id:
|
|
120
|
+
# JSON-RPC Notification (event delivery)
|
|
121
|
+
params = msg.get("params", {})
|
|
122
|
+
event_name = params.get("event", "")
|
|
147
123
|
if event_name == "module.shutdown":
|
|
148
|
-
|
|
124
|
+
data = params.get("data", {})
|
|
125
|
+
target = data.get("module_id", "")
|
|
149
126
|
if target == "assistant":
|
|
150
127
|
await self._handle_shutdown(ws)
|
|
151
128
|
return
|
|
152
|
-
elif
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
print(f"[assistant] Event Hub error: {msg.get('message')}")
|
|
129
|
+
elif not has_method and has_id:
|
|
130
|
+
# JSON-RPC Response (to our RPC calls)
|
|
131
|
+
pass
|
|
156
132
|
except Exception as e:
|
|
157
133
|
print(f"[assistant] 事件处理异常(已忽略): {e}")
|
|
158
134
|
|
|
@@ -162,64 +138,49 @@ class AssistantServer:
|
|
|
162
138
|
self._shutting_down = True
|
|
163
139
|
|
|
164
140
|
# Step 1: Send ack
|
|
165
|
-
await self.
|
|
141
|
+
await self._rpc_call(ws, "event.publish", {
|
|
142
|
+
"event_id": str(uuid.uuid4()),
|
|
166
143
|
"event": "module.shutdown.ack",
|
|
167
144
|
"data": {"module_id": "assistant", "estimated_cleanup": 2},
|
|
168
145
|
})
|
|
169
146
|
print("[assistant] shutdown ack sent")
|
|
170
147
|
|
|
171
148
|
# Step 2: Cleanup (cancel background tasks)
|
|
172
|
-
if self._heartbeat_task:
|
|
173
|
-
self._heartbeat_task.cancel()
|
|
174
149
|
if self._test_task:
|
|
175
150
|
self._test_task.cancel()
|
|
176
151
|
|
|
177
152
|
# Step 3: Send ready (before closing WS!)
|
|
178
|
-
await self.
|
|
153
|
+
await self._rpc_call(ws, "event.publish", {
|
|
154
|
+
"event_id": str(uuid.uuid4()),
|
|
179
155
|
"event": "module.shutdown.ready",
|
|
180
156
|
"data": {"module_id": "assistant"},
|
|
181
157
|
})
|
|
182
|
-
print("[assistant] Shutdown
|
|
158
|
+
print("[assistant] Shutdown ready sent")
|
|
183
159
|
|
|
184
|
-
# Step 4:
|
|
185
|
-
|
|
186
|
-
|
|
160
|
+
# Step 4: Exit process
|
|
161
|
+
import sys
|
|
162
|
+
sys.exit(0)
|
|
163
|
+
|
|
164
|
+
async def _rpc_call(self, ws, method: str, params: dict = None):
|
|
165
|
+
"""Send a JSON-RPC 2.0 request."""
|
|
166
|
+
msg = {"jsonrpc": "2.0", "id": str(uuid.uuid4()), "method": method}
|
|
167
|
+
if params:
|
|
168
|
+
msg["params"] = params
|
|
169
|
+
await ws.send(json.dumps(msg))
|
|
187
170
|
|
|
188
171
|
async def _publish_event(self, event: dict):
|
|
189
|
-
"""Publish an event
|
|
172
|
+
"""Publish an event via JSON-RPC event.publish."""
|
|
190
173
|
if not self._ws:
|
|
191
174
|
return
|
|
192
|
-
msg = {
|
|
193
|
-
"type": "event",
|
|
194
|
-
"event_id": str(uuid.uuid4()),
|
|
195
|
-
"event": event.get("event", ""),
|
|
196
|
-
"source": "assistant",
|
|
197
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
198
|
-
"data": event.get("data", {}),
|
|
199
|
-
}
|
|
200
175
|
try:
|
|
201
|
-
await self._ws.
|
|
176
|
+
await self._rpc_call(self._ws, "event.publish", {
|
|
177
|
+
"event_id": str(uuid.uuid4()),
|
|
178
|
+
"event": event.get("event", ""),
|
|
179
|
+
"data": event.get("data", {}),
|
|
180
|
+
})
|
|
202
181
|
except Exception as e:
|
|
203
182
|
print(f"[assistant] Failed to publish event: {e}")
|
|
204
183
|
|
|
205
|
-
# ── Heartbeat to Registry ──
|
|
206
|
-
|
|
207
|
-
async def _heartbeat_loop(self):
|
|
208
|
-
"""Send heartbeat to Registry every 30 seconds."""
|
|
209
|
-
while True:
|
|
210
|
-
await asyncio.sleep(30)
|
|
211
|
-
try:
|
|
212
|
-
async with httpx.AsyncClient() as client:
|
|
213
|
-
await client.post(
|
|
214
|
-
f"{self.registry_url}/modules",
|
|
215
|
-
json={"action": "heartbeat", "module_id": "assistant"},
|
|
216
|
-
headers={"Authorization": f"Bearer {self.token}"},
|
|
217
|
-
timeout=5,
|
|
218
|
-
)
|
|
219
|
-
print("[assistant] heartbeat sent")
|
|
220
|
-
except Exception:
|
|
221
|
-
pass
|
|
222
|
-
|
|
223
184
|
# ── Test event loop ──
|
|
224
185
|
|
|
225
186
|
async def _test_event_loop(self):
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
"""
|
|
2
2
|
ACP Channel entry point.
|
|
3
|
-
Reads boot_info from stdin,
|
|
3
|
+
Reads boot_info from stdin, connects to Kernel via WebSocket JSON-RPC 2.0.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import asyncio
|
|
6
7
|
import builtins
|
|
7
8
|
import json
|
|
8
9
|
import os
|
|
9
|
-
import
|
|
10
|
+
import re
|
|
10
11
|
import sys
|
|
11
12
|
import threading
|
|
12
|
-
import re
|
|
13
13
|
import time
|
|
14
|
+
import traceback
|
|
14
15
|
from datetime import datetime, timezone
|
|
15
16
|
|
|
16
|
-
import httpx
|
|
17
|
-
import uvicorn
|
|
18
|
-
|
|
19
17
|
|
|
20
18
|
# ── Safe stdout/stderr: ignore BrokenPipeError after Launcher closes stdio ──
|
|
21
19
|
|
|
@@ -240,59 +238,24 @@ def _fmt_elapsed(t0: float) -> str:
|
|
|
240
238
|
return f"{d:.0f}s"
|
|
241
239
|
|
|
242
240
|
|
|
243
|
-
def
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return s.getsockname()[1]
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
def _register_to_registry(client: httpx.Client, token: str, registry_url: str, port: int):
|
|
250
|
-
payload = {
|
|
251
|
-
"action": "register",
|
|
252
|
-
"module_id": "acp_channel",
|
|
253
|
-
"module_type": "channel",
|
|
254
|
-
"name": "ACP Channel",
|
|
255
|
-
"api_endpoint": f"http://127.0.0.1:{port}",
|
|
256
|
-
"health_endpoint": "/health",
|
|
257
|
-
"events_publish": {
|
|
258
|
-
"acp_channel.test": {"description": "Test event from acp_channel module"},
|
|
259
|
-
},
|
|
260
|
-
"events_subscribe": [
|
|
261
|
-
"module.started",
|
|
262
|
-
"module.stopped",
|
|
263
|
-
"module.shutdown",
|
|
264
|
-
],
|
|
265
|
-
}
|
|
266
|
-
headers = {"Authorization": f"Bearer {token}"}
|
|
267
|
-
try:
|
|
268
|
-
resp = client.post(f"{registry_url}/modules", json=payload, headers=headers)
|
|
269
|
-
if resp.status_code == 200:
|
|
270
|
-
pass # timing printed in main()
|
|
271
|
-
else:
|
|
272
|
-
print(f"[acp_channel] WARNING: Registry returned {resp.status_code}")
|
|
273
|
-
except Exception as e:
|
|
274
|
-
print(f"[acp_channel] WARNING: Registry registration failed: {e}")
|
|
275
|
-
|
|
241
|
+
def _read_stdin_kite_message(expected_type: str, timeout: float = 10) -> dict | None:
|
|
242
|
+
"""Read a single kite message of expected type from stdin with timeout."""
|
|
243
|
+
result = [None]
|
|
276
244
|
|
|
277
|
-
def
|
|
278
|
-
"""Discover Event Hub WebSocket endpoint from Registry, with retry."""
|
|
279
|
-
import time
|
|
280
|
-
headers = {"Authorization": f"Bearer {token}"}
|
|
281
|
-
deadline = time.time() + 10
|
|
282
|
-
while time.time() < deadline:
|
|
245
|
+
def _read():
|
|
283
246
|
try:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
val = resp.json()
|
|
290
|
-
if val:
|
|
291
|
-
return val
|
|
247
|
+
line = sys.stdin.readline().strip()
|
|
248
|
+
if line:
|
|
249
|
+
msg = json.loads(line)
|
|
250
|
+
if isinstance(msg, dict) and msg.get("kite") == expected_type:
|
|
251
|
+
result[0] = msg
|
|
292
252
|
except Exception:
|
|
293
253
|
pass
|
|
294
|
-
|
|
295
|
-
|
|
254
|
+
|
|
255
|
+
t = threading.Thread(target=_read, daemon=True)
|
|
256
|
+
t.start()
|
|
257
|
+
t.join(timeout=timeout)
|
|
258
|
+
return result[0]
|
|
296
259
|
|
|
297
260
|
|
|
298
261
|
def main():
|
|
@@ -334,42 +297,28 @@ def main():
|
|
|
334
297
|
except Exception:
|
|
335
298
|
pass
|
|
336
299
|
|
|
337
|
-
# Read
|
|
338
|
-
|
|
300
|
+
# Read kernel_port: env first (fast path), stdin fallback (parallel start)
|
|
301
|
+
kernel_port = int(os.environ.get("KITE_KERNEL_PORT", "0"))
|
|
302
|
+
if not kernel_port:
|
|
303
|
+
msg = _read_stdin_kite_message("kernel_port", timeout=10)
|
|
304
|
+
if msg:
|
|
305
|
+
kernel_port = int(msg.get("kernel_port", 0))
|
|
339
306
|
|
|
340
|
-
if not token or not
|
|
341
|
-
print("[acp_channel] ERROR: Missing token or
|
|
307
|
+
if not token or not kernel_port:
|
|
308
|
+
print("[acp_channel] ERROR: Missing token or kernel_port")
|
|
342
309
|
sys.exit(1)
|
|
343
310
|
|
|
344
|
-
print(f"[acp_channel] Token received ({len(token)} chars),
|
|
345
|
-
|
|
346
|
-
registry_url = f"http://127.0.0.1:{registry_port}"
|
|
347
|
-
port = _get_free_port()
|
|
348
|
-
|
|
349
|
-
# Register and discover Event Hub synchronously before starting uvicorn
|
|
350
|
-
client = httpx.Client(timeout=5)
|
|
351
|
-
_register_to_registry(client, token, registry_url, port)
|
|
352
|
-
print(f"[acp_channel] Registered to Registry ({_fmt_elapsed(_t0)})")
|
|
353
|
-
event_hub_ws = _get_event_hub_ws(client, token, registry_url)
|
|
354
|
-
if not event_hub_ws:
|
|
355
|
-
print("[acp_channel] WARNING: Could not discover Event Hub WS, events disabled")
|
|
356
|
-
else:
|
|
357
|
-
print(f"[acp_channel] Discovered Event Hub: {event_hub_ws}")
|
|
358
|
-
client.close()
|
|
311
|
+
print(f"[acp_channel] Token received ({len(token)} chars), kernel port: {kernel_port} ({_fmt_elapsed(_t0)})")
|
|
359
312
|
|
|
360
313
|
server = AcpChannelServer(
|
|
361
314
|
token=token,
|
|
362
|
-
|
|
363
|
-
event_hub_ws=event_hub_ws,
|
|
315
|
+
kernel_port=kernel_port,
|
|
364
316
|
boot_t0=_t0,
|
|
365
317
|
)
|
|
366
318
|
|
|
367
|
-
print(f"[acp_channel] Starting
|
|
319
|
+
print(f"[acp_channel] Starting ({_fmt_elapsed(_t0)})")
|
|
368
320
|
try:
|
|
369
|
-
|
|
370
|
-
uvi_server = uvicorn.Server(config)
|
|
371
|
-
server._uvicorn_server = uvi_server
|
|
372
|
-
uvi_server.run()
|
|
321
|
+
asyncio.run(server.run())
|
|
373
322
|
except Exception as e:
|
|
374
323
|
_write_crash(type(e), e, e.__traceback__, severity="critical", handled=True)
|
|
375
324
|
_print_crash_summary(type(e), e.__traceback__)
|