feat(backend): full remote implementation, untested
This commit is contained in:
1 parent
0705f4abc5
commit
5009a4eb4c
8 files changed
+485
-33
No files matched your search
+62
-7
@@ -127,7 +127,7 @@ async def start_server(app, shutdown_event):
|
||||
await websocket.send(json.dumps({'error': 'invalid auth'}))
|
||||
return
|
||||
|
||||
user_id = app.verify_user_credentials(auth_req['username'], auth_req['password'])
|
||||
user_id = await app.verify_user_credentials(auth_req['username'], auth_req['password'])
|
||||
if user_id is None:
|
||||
print("Invalid Credentials");
|
||||
await websocket.send(json.dumps({'error': 'invalid credentials'}))
|
||||
@@ -150,13 +150,13 @@ async def start_server(app, shutdown_event):
|
||||
ws_task = asyncio.current_task()
|
||||
app.ws_tasks.append(ws_task)
|
||||
|
||||
session_connections = {} # remotename -> RemoteConnection served by this socket
|
||||
stop_listening = None
|
||||
try:
|
||||
# TODO: remotes aren't separate connections
|
||||
# instead, any connection can create a remotes and listen for requests sent to them
|
||||
if 'remotename' in auth_req:
|
||||
app.add_remote_connection(user_id, authreq['remotename'], authreq['tools'], send_queue)
|
||||
else:
|
||||
app.add_user_connection(user_id, send_queue)
|
||||
# All sessions are identical after authentication: every session
|
||||
# is a user connection, and any session can additionally connect
|
||||
# remotes ('remote-connect' action) and serve calls on them.
|
||||
app.add_user_connection(user_id, send_queue)
|
||||
|
||||
# Listen for events and broadcast them
|
||||
async def on_event(name, data):
|
||||
@@ -258,6 +258,52 @@ async def start_server(app, shutdown_event):
|
||||
elif action == "cancel-agent-run":
|
||||
await app.cancel_agent_run(body['runId'])
|
||||
|
||||
elif action == "remote-list":
|
||||
await send({'remotes': app.listRemotes(user_id), 'nonce': nonce})
|
||||
|
||||
elif action == "remote-connect":
|
||||
# Connect a remote served by THIS session's channel.
|
||||
# Expected failures (duplicate name) are replied, not
|
||||
# raised, so the session stays alive.
|
||||
try:
|
||||
connection = app.connectRemote(user_id, body['remotename'], body.get('functions', []), send)
|
||||
session_connections[body['remotename']] = connection
|
||||
await send({'message': "remote connected", 'remotename': body['remotename'], 'nonce': nonce})
|
||||
except Exception as e:
|
||||
await send({'error': str(e), 'nonce': nonce})
|
||||
|
||||
elif action == "remote-disconnect":
|
||||
# Manual disconnect, allowed from any session of the user
|
||||
connection = app.disconnectRemote(user_id, body['remotename'])
|
||||
session_connections.pop(body['remotename'], None)
|
||||
if connection is None:
|
||||
await send({'error': "no connected remote named '" + str(body['remotename']) + "'", 'nonce': nonce})
|
||||
else:
|
||||
await send({'message': "remote disconnected", 'remotename': body['remotename'], 'nonce': nonce})
|
||||
|
||||
elif action == "remote-call":
|
||||
# Invoke a function of one of the user's connected remotes.
|
||||
# Expected failures (unknown remote/function, timeout,
|
||||
# remote-side error) are replied, not raised.
|
||||
try:
|
||||
result = await app.callRemote(user_id, body['remotename'], body['function'], body.get('args', {}))
|
||||
await send({'result': result, 'nonce': nonce})
|
||||
except Exception as e:
|
||||
await send({'error': str(e), 'nonce': nonce})
|
||||
|
||||
elif action == "remote-call-result":
|
||||
# A session serving remotes replies to a downstream call.
|
||||
# Fields live at the message top level, not in 'body'.
|
||||
# requestIds are '<remotename>#<n>' and resolve/reject
|
||||
# are no-ops for unknown ids, so fanning out over this
|
||||
# session's connections routes the reply correctly.
|
||||
if 'error' in req:
|
||||
for conn in session_connections.values():
|
||||
conn.reject(req.get('requestId'), req['error'])
|
||||
else:
|
||||
for conn in session_connections.values():
|
||||
conn.resolve(req.get('requestId'), req.get('result'))
|
||||
|
||||
elif action == "create-chat":
|
||||
chat_id = await app.create_chat(
|
||||
user_id=user_id,
|
||||
@@ -351,6 +397,15 @@ async def start_server(app, shutdown_event):
|
||||
print("User logged out:", user_id)
|
||||
if ws_task in app.ws_tasks:
|
||||
app.ws_tasks.remove(ws_task)
|
||||
# Unregister the event listener: the send closure would
|
||||
# otherwise keep queueing events for a dead socket forever
|
||||
if stop_listening:
|
||||
stop_listening()
|
||||
# All remotes served by this session are disconnected with it.
|
||||
# disconnectRemote is idempotent, so remotes that were already
|
||||
# disconnected manually (possibly from another session) are safe.
|
||||
for remotename in list(session_connections):
|
||||
app.disconnectRemote(user_id, remotename)
|
||||
app.remove_user_connection(user_id, send_queue)
|
||||
|
||||
# https://github.com/hrgarber/openai-compatible-api/blob/main/app/main.py
|
||||
|
||||
Reference in new issue
Block a user