Skip to content

Commit 72e7601

Browse files
committed
feat: connector for plugin runtime
1 parent c642a4a commit 72e7601

File tree

9 files changed

+130
-34
lines changed

9 files changed

+130
-34
lines changed

pkg/core/app.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from ..config import manager as config_mgr
1414
from ..command import cmdmgr
1515
from ..plugin import manager as plugin_mgr
16+
from ..plugin import connector as plugin_connector
1617
from ..pipeline import pool
1718
from ..pipeline import controller, pipelinemgr
1819
from ..utils import version as version_mgr, proxy as proxy_mgr, announce as announce_mgr
@@ -77,6 +78,8 @@ class Application:
7778

7879
plugin_mgr: plugin_mgr.PluginManager = None
7980

81+
plugin_connector: plugin_connector.PluginRuntimeConnector = None
82+
8083
query_pool: pool.QueryPool = None
8184

8285
ctrl: controller.Controller = None
@@ -117,6 +120,8 @@ async def initialize(self):
117120

118121
async def run(self):
119122
try:
123+
await self.plugin_connector.initialize_plugins()
124+
120125
await self.plugin_mgr.initialize_plugins()
121126

122127
# 后续可能会允许动态重启其他任务

pkg/core/stages/build_app.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from ...utils import version, proxy, announce
66
from ...pipeline import pool, controller, pipelinemgr
77
from ...plugin import manager as plugin_mgr
8+
from ...plugin import connector as plugin_connector
89
from ...command import cmdmgr
910
from ...provider.session import sessionmgr as llm_session_mgr
1011
from ...provider.modelmgr import modelmgr as llm_model_mgr
@@ -64,6 +65,10 @@ async def run(self, ap: app.Application):
6465
ap.plugin_mgr = plugin_mgr_inst
6566
await plugin_mgr_inst.load_plugins()
6667

68+
plugin_connector_inst = plugin_connector.PluginRuntimeConnector(ap)
69+
await plugin_connector_inst.initialize()
70+
ap.plugin_connector = plugin_connector_inst
71+
6772
cmd_mgr_inst = cmdmgr.CommandManager(ap)
6873
await cmd_mgr_inst.initialize()
6974
ap.cmd_mgr = cmd_mgr_inst

pkg/persistence/mgr.py

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,38 @@ async def initialize(self):
4444

4545
await self.create_tables()
4646

47+
# run migrations
48+
database_version = await self.execute_async(
49+
sqlalchemy.select(metadata.Metadata).where(metadata.Metadata.key == 'database_version')
50+
)
51+
52+
database_version = int(database_version.fetchone()[1])
53+
required_database_version = constants.required_database_version
54+
55+
if database_version < required_database_version:
56+
migrations = migration.preregistered_db_migrations
57+
migrations.sort(key=lambda x: x.number)
58+
59+
last_migration_number = database_version
60+
61+
for migration_cls in migrations:
62+
migration_instance = migration_cls(self.ap)
63+
64+
if (
65+
migration_instance.number > database_version
66+
and migration_instance.number <= required_database_version
67+
):
68+
await migration_instance.upgrade()
69+
await self.execute_async(
70+
sqlalchemy.update(metadata.Metadata)
71+
.where(metadata.Metadata.key == 'database_version')
72+
.values({'value': str(migration_instance.number)})
73+
)
74+
last_migration_number = migration_instance.number
75+
self.ap.logger.info(f'Migration {migration_instance.number} completed.')
76+
77+
self.ap.logger.info(f'Successfully upgraded database to version {last_migration_number}.')
78+
4779
async def create_tables(self):
4880
# create tables
4981
async with self.get_db_engine().connect() as conn:
@@ -87,38 +119,6 @@ async def create_tables(self):
87119

88120
# =================================
89121

90-
# run migrations
91-
database_version = await self.execute_async(
92-
sqlalchemy.select(metadata.Metadata).where(metadata.Metadata.key == 'database_version')
93-
)
94-
95-
database_version = int(database_version.fetchone()[1])
96-
required_database_version = constants.required_database_version
97-
98-
if database_version < required_database_version:
99-
migrations = migration.preregistered_db_migrations
100-
migrations.sort(key=lambda x: x.number)
101-
102-
last_migration_number = database_version
103-
104-
for migration_cls in migrations:
105-
migration_instance = migration_cls(self.ap)
106-
107-
if (
108-
migration_instance.number > database_version
109-
and migration_instance.number <= required_database_version
110-
):
111-
await migration_instance.upgrade()
112-
await self.execute_async(
113-
sqlalchemy.update(metadata.Metadata)
114-
.where(metadata.Metadata.key == 'database_version')
115-
.values({'value': str(migration_instance.number)})
116-
)
117-
last_migration_number = migration_instance.number
118-
self.ap.logger.info(f'Migration {migration_instance.number} completed.')
119-
120-
self.ap.logger.info(f'Successfully upgraded database to version {last_migration_number}.')
121-
122122
async def execute_async(self, *args, **kwargs) -> sqlalchemy.engine.cursor.CursorResult:
123123
async with self.get_db_engine().connect() as conn:
124124
result = await conn.execute(*args, **kwargs)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from .. import migration
2+
3+
4+
@migration.migration_class(4)
5+
class DBMigratePluginConfig(migration.DBMigration):
6+
"""插件配置"""
7+
8+
async def upgrade(self):
9+
"""升级"""
10+
11+
if 'plugin' not in self.ap.instance_config.data:
12+
self.ap.instance_config.data['plugin'] = {
13+
'runtime_ws_url': 'ws://localhost:5400/control/ws',
14+
}
15+
16+
await self.ap.instance_config.dump_config()
17+
18+
async def downgrade(self):
19+
"""降级"""
20+
pass

pkg/plugin/connector.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# For connect to plugin runtime.
2+
from __future__ import annotations
3+
4+
import asyncio
5+
import os
6+
import sys
7+
8+
from ..core import app
9+
from . import handler
10+
from ..utils import platform
11+
from langbot_plugin.runtime.io.controllers.stdio import client as stdio_client_controller
12+
from langbot_plugin.runtime.io.connections import stdio as stdio_connection
13+
from langbot_plugin.runtime.io.controllers.ws import client as ws_client_controller
14+
15+
16+
class PluginRuntimeConnector:
17+
"""Plugin runtime connector"""
18+
19+
ap: app.Application
20+
21+
handler: handler.RuntimeConnectionHandler
22+
23+
handler_task: asyncio.Task
24+
25+
stdio_client_controller: stdio_client_controller.StdioClientController
26+
27+
def __init__(self, ap: app.Application):
28+
self.ap = ap
29+
30+
async def initialize(self):
31+
async def new_connection_callback(connection: stdio_connection.StdioConnection):
32+
self.ap.logger.info('Connected to plugin runtime.')
33+
self.handler = handler.RuntimeConnectionHandler(connection)
34+
self.handler_task = asyncio.create_task(self.handler.run())
35+
36+
if platform.get_platform() == 'docker': # use websocket
37+
ws_url = self.ap.instance_config.data['plugin']['runtime_ws_url']
38+
ctrl = ws_client_controller.WebSocketClientController(
39+
ws_url=ws_url,
40+
)
41+
await ctrl.run(new_connection_callback)
42+
else: # stdio
43+
# cmd: lbp rt -s
44+
python_path = sys.executable
45+
env = os.environ.copy()
46+
ctrl = stdio_client_controller.StdioClientController(
47+
command=python_path,
48+
args=['-m', 'langbot_plugin.cli.__init__', 'rt', '-s'],
49+
env=env,
50+
)
51+
await ctrl.run(new_connection_callback)
52+
53+
async def run(self):
54+
pass
55+
56+
async def initialize_plugins(self):
57+
pass

pkg/plugin/handler.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from __future__ import annotations
2+
3+
from langbot_plugin.runtime.io import handler
4+
5+
6+
class RuntimeConnectionHandler(handler.Handler):
7+
"""Runtime connection handler"""

pkg/utils/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
semantic_version = 'v4.0.5'
22

3-
required_database_version = 3
3+
required_database_version = 4
44
"""标记本版本所需要的数据库结构版本,用于判断数据库迁移"""
55

66
debug_mode = False

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ dependencies = [
5050
"pre-commit>=4.2.0",
5151
"uv>=0.7.11",
5252
"mypy>=1.16.0",
53-
"langbot-plugin>=0.1.0a4",
53+
"langbot-plugin==0.1.0a6",
5454
]
5555
keywords = [
5656
"bot",

templates/config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ system:
1818
jwt:
1919
expire: 604800
2020
secret: ''
21+
plugin:
22+
runtime_ws_url: 'ws://plugin-runtime:5400/control/ws'

0 commit comments

Comments
 (0)