langbot-plugin 0.1.0__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.
Files changed (34) hide show
  1. langbot_plugin/__init__.py +0 -0
  2. langbot_plugin/api/__init__.py +0 -0
  3. langbot_plugin/cli/__init__.py +35 -0
  4. langbot_plugin/cli/command.py +9 -0
  5. langbot_plugin/cli/commands/__init__.py +0 -0
  6. langbot_plugin/entities/__init__.py +0 -0
  7. langbot_plugin/entities/io/__init__.py +0 -0
  8. langbot_plugin/entities/io/errors.py +31 -0
  9. langbot_plugin/entities/io/req.py +16 -0
  10. langbot_plugin/entities/io/resp.py +19 -0
  11. langbot_plugin/runtime/__init__.py +0 -0
  12. langbot_plugin/runtime/__main__.py +10 -0
  13. langbot_plugin/runtime/app.py +60 -0
  14. langbot_plugin/runtime/controller/__init__.py +0 -0
  15. langbot_plugin/runtime/controller/stdio/__init__.py +0 -0
  16. langbot_plugin/runtime/controller/stdio/server.py +18 -0
  17. langbot_plugin/runtime/controller/ws/__init__.py +0 -0
  18. langbot_plugin/runtime/controller/ws/server.py +74 -0
  19. langbot_plugin/runtime/core/__init__.py +0 -0
  20. langbot_plugin/runtime/io/connection.py +19 -0
  21. langbot_plugin/runtime/io/connections/__init__.py +0 -0
  22. langbot_plugin/runtime/io/connections/stdio.py +24 -0
  23. langbot_plugin/runtime/io/connections/ws.py +26 -0
  24. langbot_plugin/runtime/io/handler.py +129 -0
  25. langbot_plugin/runtime/io/handlers/__init__.py +0 -0
  26. langbot_plugin/runtime/io/handlers/control.py +23 -0
  27. langbot_plugin/runtime/service/__init__.py +0 -0
  28. langbot_plugin/utils/__init__.py +0 -0
  29. langbot_plugin/utils/importutil.py +38 -0
  30. langbot_plugin/version.py +1 -0
  31. langbot_plugin-0.1.0.dist-info/METADATA +30 -0
  32. langbot_plugin-0.1.0.dist-info/RECORD +34 -0
  33. langbot_plugin-0.1.0.dist-info/WHEEL +4 -0
  34. langbot_plugin-0.1.0.dist-info/entry_points.txt +2 -0
File without changes
File without changes
@@ -0,0 +1,35 @@
1
+ import argparse
2
+ from langbot_plugin.version import __version__
3
+ from langbot_plugin.runtime import __main__ as runtime_main
4
+
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(description="LangBot Plugin CLI")
8
+
9
+ subparsers = parser.add_subparsers(dest="command")
10
+
11
+ version_parser = subparsers.add_parser("ver", help="Show the version of the CLI")
12
+
13
+ init_parser = subparsers.add_parser("init", help="Initialize a new plugin")
14
+ init_parser.add_argument(
15
+ "--name", "-n", action="store", type=str, help="The name of the plugin"
16
+ )
17
+
18
+ runtime_parser = subparsers.add_parser("rt", help="Run the runtime")
19
+ runtime_parser.add_argument(
20
+ "--stdio-control", "-s", action="store_true", default=False
21
+ )
22
+ runtime_parser.add_argument("--ws-control-port", type=int, default=5400)
23
+ runtime_parser.add_argument("--ws-debug-port", type=int, default=5401)
24
+
25
+ args = parser.parse_args()
26
+
27
+ match args.command:
28
+ case "ver":
29
+ print(f"LangBot Plugin CLI v{__version__}")
30
+ case "init":
31
+ print(f"Initializing plugin {args.name}")
32
+ case "rt":
33
+ runtime_main.main(args)
34
+ case _:
35
+ print(f"Unknown command: {args.command}")
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+
5
+
6
+ class CLICommand(abc.ABC):
7
+ @abc.abstractmethod
8
+ def run(self):
9
+ pass
File without changes
File without changes
File without changes
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class ConnectionClosedError(Exception):
5
+ """The connection is closed."""
6
+
7
+ def __init__(self, message: str):
8
+ self.message = message
9
+
10
+ def __str__(self):
11
+ return self.message
12
+
13
+
14
+ class ActionCallTimeoutError(Exception):
15
+ """The action call timed out."""
16
+
17
+ def __init__(self, message: str):
18
+ self.message = message
19
+
20
+ def __str__(self):
21
+ return self.message
22
+
23
+
24
+ class ActionCallError(Exception):
25
+ """The action call failed."""
26
+
27
+ def __init__(self, message: str):
28
+ self.message = message
29
+
30
+ def __str__(self):
31
+ return self.message
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ import pydantic
4
+ from typing import Any
5
+
6
+
7
+ class ActionRequest(pydantic.BaseModel):
8
+ seq_id: int = pydantic.Field(..., description="The sequence id of the request")
9
+ action: str
10
+ data: dict[str, Any]
11
+
12
+ @classmethod
13
+ def make_request(
14
+ cls, seq_id: int, action: str, data: dict[str, Any]
15
+ ) -> ActionRequest:
16
+ return cls(seq_id=seq_id, action=action, data=data)
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ import pydantic
4
+ from typing import Any, Optional
5
+
6
+
7
+ class ActionResponse(pydantic.BaseModel):
8
+ seq_id: Optional[int] = None
9
+ code: int = pydantic.Field(..., description="The code of the response")
10
+ message: str = pydantic.Field(..., description="The message of the response")
11
+ data: dict[str, Any] = pydantic.Field(..., description="The data of the response")
12
+
13
+ @classmethod
14
+ def success(cls, data: dict[str, Any]) -> ActionResponse:
15
+ return cls(seq_id=0, code=0, message="success", data=data)
16
+
17
+ @classmethod
18
+ def error(cls, message: str) -> ActionResponse:
19
+ return cls(code=1, message=message, data={})
File without changes
@@ -0,0 +1,10 @@
1
+ # handler for command
2
+ import asyncio
3
+ import argparse
4
+
5
+ from langbot_plugin.runtime.app import Application
6
+
7
+
8
+ def main(args: argparse.Namespace):
9
+ app = Application(args)
10
+ asyncio.run(app.run())
@@ -0,0 +1,60 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from enum import Enum
5
+
6
+ import asyncio
7
+
8
+ from langbot_plugin.runtime.controller.stdio import server as stdio_controller_server
9
+ from langbot_plugin.runtime.controller.ws import server as ws_controller_server
10
+ from langbot_plugin.runtime.io import handler
11
+
12
+
13
+ class ControlConnectionMode(Enum):
14
+ STDIO = "stdio"
15
+ WS = "ws"
16
+
17
+
18
+ class Application:
19
+ """Runtime application context."""
20
+
21
+ handler_manager: handler.HandlerManager
22
+
23
+ control_connection_mode: ControlConnectionMode
24
+
25
+ stdio_server: stdio_controller_server.StdioServer | None = (
26
+ None # stdio control server
27
+ )
28
+ ws_server: ws_controller_server.WebSocketServer | None = (
29
+ None # ws control/debug server
30
+ )
31
+
32
+ def __init__(self, args: argparse.Namespace):
33
+ self.args = args
34
+ self.handler_manager = handler.HandlerManager()
35
+
36
+ if args.stdio_control:
37
+ self.control_connection_mode = ControlConnectionMode.STDIO
38
+ else:
39
+ self.control_connection_mode = ControlConnectionMode.WS
40
+
41
+ # build controllers layer
42
+ if self.control_connection_mode == ControlConnectionMode.STDIO:
43
+ self.stdio_server = stdio_controller_server.StdioServer(
44
+ self.handler_manager
45
+ )
46
+
47
+ self.ws_server = ws_controller_server.WebSocketServer(
48
+ self.args.ws_control_port, self.args.ws_debug_port, self.handler_manager
49
+ )
50
+
51
+ async def run(self):
52
+ tasks = []
53
+
54
+ if self.stdio_server:
55
+ tasks.append(self.stdio_server.run())
56
+
57
+ if self.ws_server:
58
+ tasks.append(self.ws_server.run())
59
+
60
+ await asyncio.gather(*tasks)
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ # Stdio server for LangBot control connection
2
+ from __future__ import annotations
3
+
4
+ from langbot_plugin.runtime.io.connections import stdio as stdio_connection
5
+ from langbot_plugin.runtime.io.handlers import control as control_handler
6
+ from langbot_plugin.runtime.io import handler as io_handler
7
+
8
+
9
+ class StdioServer:
10
+ def __init__(self, handler_manager: io_handler.HandlerManager):
11
+ self.handler_manager = handler_manager
12
+
13
+ async def run(self):
14
+ print("Starting Stdio server")
15
+ connection = stdio_connection.StdioConnection()
16
+ handler = control_handler.ControlConnectionHandler(connection)
17
+ task = self.handler_manager.set_control_handler(handler)
18
+ await task
File without changes
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import websockets
5
+
6
+ from langbot_plugin.runtime.io.connections import ws as ws_connection
7
+ from langbot_plugin.runtime.io.handlers import control as control_handler
8
+ from langbot_plugin.runtime.io import handler as io_handler
9
+
10
+
11
+ class ControlConnectionWebSocketServer:
12
+ """The server for control connection WebSocket connections."""
13
+
14
+ def __init__(self, port: int, handler_manager: io_handler.HandlerManager):
15
+ self.port = port
16
+ self.handler_manager = handler_manager
17
+
18
+ async def run(self):
19
+ server = await websockets.serve(self.handle_connection, "0.0.0.0", self.port)
20
+ await server.wait_closed()
21
+
22
+ async def handle_connection(self, websocket: websockets.ServerConnection):
23
+ print(f"New control connection from {websocket.remote_address}")
24
+ connection = ws_connection.WebSocketConnection(websocket)
25
+ handler = control_handler.ControlConnectionHandler(connection)
26
+ task = self.handler_manager.set_control_handler(handler)
27
+ await task
28
+
29
+
30
+ class DebugConnectionWebSocketServer:
31
+ """The server for debug connection WebSocket connections."""
32
+
33
+ def __init__(self, port: int, handler_manager: io_handler.HandlerManager):
34
+ self.port = port
35
+ self.handler_manager = handler_manager
36
+
37
+ async def run(self):
38
+ server = await websockets.serve(self.handle_connection, "0.0.0.0", self.port)
39
+ await server.wait_closed()
40
+
41
+ async def handle_connection(self, websocket: websockets.ServerConnection):
42
+ print(f"New connection from {websocket.remote_address}")
43
+ await websocket.send("Hello, world!")
44
+ await websocket.close()
45
+
46
+
47
+ class WebSocketServer:
48
+ """The server for control connection WebSocket connections."""
49
+
50
+ def __init__(
51
+ self,
52
+ control_port: int,
53
+ debug_port: int,
54
+ handler_manager: io_handler.HandlerManager,
55
+ ):
56
+ self.control_port = control_port
57
+ self.debug_port = debug_port
58
+ self.handler_manager = handler_manager
59
+
60
+ async def run(self):
61
+ print(
62
+ f"Starting WebSocket server on port {self.control_port} for control connections"
63
+ )
64
+ print(
65
+ f"Starting WebSocket server on port {self.debug_port} for debug connections"
66
+ )
67
+ control_server = ControlConnectionWebSocketServer(
68
+ self.control_port, self.handler_manager
69
+ )
70
+ debug_server = DebugConnectionWebSocketServer(
71
+ self.debug_port, self.handler_manager
72
+ )
73
+
74
+ await asyncio.gather(control_server.run(), debug_server.run())
File without changes
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+
5
+
6
+ class Connection(abc.ABC):
7
+ """The abstract base class for all connections."""
8
+
9
+ @abc.abstractmethod
10
+ async def send(self, message: str) -> None:
11
+ pass
12
+
13
+ @abc.abstractmethod
14
+ async def receive(self) -> str:
15
+ pass
16
+
17
+ @abc.abstractmethod
18
+ async def close(self) -> None:
19
+ pass
File without changes
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+
5
+ from langbot_plugin.runtime.io import connection
6
+
7
+
8
+ class StdioConnection(connection.Connection):
9
+ """The connection for Stdio connections."""
10
+
11
+ def __init__(self):
12
+ pass
13
+
14
+ async def send(self, message: str) -> None:
15
+ print(message)
16
+
17
+ async def receive(self) -> str:
18
+ while True:
19
+ s = await asyncio.to_thread(input)
20
+ if s.startswith("{") and s.endswith("}"):
21
+ return s
22
+
23
+ async def close(self) -> None:
24
+ pass
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import websockets
4
+
5
+ from langbot_plugin.runtime.io import connection as io_connection
6
+ from langbot_plugin.entities.io.errors import ConnectionClosedError
7
+
8
+
9
+ class WebSocketConnection(io_connection.Connection):
10
+ """The connection for WebSocket connections."""
11
+
12
+ def __init__(self, websocket: websockets.ServerConnection):
13
+ self.websocket = websocket
14
+
15
+ async def send(self, message: str) -> None:
16
+ await self.websocket.send(message, text=True)
17
+
18
+ async def receive(self) -> str:
19
+ try:
20
+ data = await self.websocket.recv(decode=True)
21
+ return data
22
+ except websockets.exceptions.ConnectionClosed:
23
+ raise ConnectionClosedError("Connection closed")
24
+
25
+ async def close(self) -> None:
26
+ await self.websocket.close()
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+ import asyncio
5
+ import json
6
+ from typing import Callable, Any, Dict, Awaitable, Coroutine
7
+
8
+ import pydantic
9
+
10
+ from langbot_plugin.runtime.io import connection
11
+ from langbot_plugin.entities.io.req import ActionRequest
12
+ from langbot_plugin.entities.io.resp import ActionResponse
13
+ from langbot_plugin.entities.io.errors import (
14
+ ConnectionClosedError,
15
+ ActionCallTimeoutError,
16
+ ActionCallError,
17
+ )
18
+
19
+
20
+ class Handler(abc.ABC):
21
+ """The abstract base class for all handlers."""
22
+
23
+ conn: connection.Connection
24
+
25
+ actions: dict[str, Callable[[dict[str, Any]], Coroutine[Any, Any, ActionResponse]]]
26
+
27
+ resp_waiters: dict[int, asyncio.Future[ActionResponse]] = {}
28
+
29
+ seq_id_index: int = 0
30
+
31
+ def __init__(self, connection: connection.Connection):
32
+ self.conn = connection
33
+ self.actions = {}
34
+
35
+ async def run(self) -> None:
36
+ while True:
37
+ message = None
38
+ try:
39
+ message = await self.conn.receive()
40
+ except ConnectionClosedError:
41
+ print("Connection closed")
42
+ break
43
+ if message is None:
44
+ continue
45
+
46
+ async def handle_message(message: str):
47
+ # sh*t, i dont really know how to use generic type here
48
+ # so just use dict[str, Any] for now
49
+ req_data = json.loads(message)
50
+ seq_id = req_data["seq_id"] if "seq_id" in req_data else -1
51
+
52
+ if "action" in req_data: # action request from peer
53
+ try:
54
+ if req_data["action"] not in self.actions:
55
+ raise ValueError(f"Action {req_data['action']} not found")
56
+
57
+ response = await self.actions[req_data["action"]](
58
+ req_data["data"]
59
+ )
60
+ response.seq_id = seq_id
61
+ await self.conn.send(json.dumps(response.model_dump()))
62
+ except Exception as e:
63
+ error_response = ActionResponse.error(
64
+ f"{e.__class__.__name__}: {str(e)}"
65
+ )
66
+ error_response.seq_id = seq_id
67
+ await self.conn.send(json.dumps(error_response.model_dump()))
68
+
69
+ elif "code" in req_data: # action response from peer
70
+ if seq_id in self.resp_waiters:
71
+ response = ActionResponse.success(req_data["data"])
72
+ response.seq_id = seq_id
73
+ self.resp_waiters[seq_id].set_result(response)
74
+ del self.resp_waiters[seq_id]
75
+
76
+ asyncio.create_task(handle_message(message))
77
+
78
+ async def call_action(
79
+ self, action: str, data: dict[str, Any], timeout: float = 10.0
80
+ ) -> dict[str, Any]:
81
+ """Actively call an action provided by the peer, and wait for the response."""
82
+ self.seq_id_index += 1
83
+ request = ActionRequest.make_request(self.seq_id_index, action, data)
84
+ await self.conn.send(json.dumps(request.model_dump()))
85
+ # wait for response
86
+ future = asyncio.Future[ActionResponse]()
87
+ self.resp_waiters[self.seq_id_index] = future
88
+ try:
89
+ response = await asyncio.wait_for(future, timeout)
90
+ if response.code != 0:
91
+ raise ActionCallError(f"{response.message}")
92
+ return response.data
93
+ except asyncio.TimeoutError:
94
+ raise ActionCallTimeoutError(f"Action {action} call timed out")
95
+ except Exception as e:
96
+ raise ActionCallError(f"{e.__class__.__name__}: {str(e)}")
97
+
98
+ # decorator to register an action
99
+ def action(
100
+ self, name: str
101
+ ) -> Callable[
102
+ [Callable[[dict[str, Any]], Coroutine[Any, Any, ActionResponse]]],
103
+ Callable[[dict[str, Any]], Coroutine[Any, Any, ActionResponse]],
104
+ ]:
105
+ def decorator(
106
+ func: Callable[[dict[str, Any]], Coroutine[Any, Any, ActionResponse]],
107
+ ) -> Callable[[dict[str, Any]], Coroutine[Any, Any, ActionResponse]]:
108
+ self.actions[name] = func
109
+ return func
110
+
111
+ return decorator
112
+
113
+
114
+ class HandlerManager:
115
+ """The manager for handlers."""
116
+
117
+ control_handler: Handler
118
+ plugin_handlers: dict[str, Handler]
119
+
120
+ def __init__(self):
121
+ self.langbot_handler = None
122
+ self.plugin_handlers = {}
123
+
124
+ def set_control_handler(self, handler: Handler) -> asyncio.Task:
125
+ self.control_handler = handler
126
+ return asyncio.create_task(handler.run())
127
+
128
+ def set_plugin_handler(self, name: str, handler: Handler) -> None:
129
+ self.plugin_handlers[name] = handler
File without changes
@@ -0,0 +1,23 @@
1
+ # handle connection from LangBot
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from langbot_plugin.runtime.io import handler, connection
7
+
8
+
9
+ class ControlConnectionHandler(handler.Handler):
10
+ """The handler for control connection."""
11
+
12
+ def __init__(self, connection: connection.Connection):
13
+ super().__init__(connection)
14
+
15
+ @self.action("ping")
16
+ async def ping(data: dict[str, Any]) -> handler.ActionResponse:
17
+ resp = await self.call_action("ping", {}, 10)
18
+ print("received resp: ", resp)
19
+ return handler.ActionResponse.success({"message": "pong"})
20
+
21
+
22
+ # {"action": "ping", "data": {}, "seq_id": 1}
23
+ # {"code": 0, "message": "ok", "data": {"msg": "hello"}, "seq_id": 1}
File without changes
File without changes
@@ -0,0 +1,38 @@
1
+ import importlib
2
+ import importlib.util
3
+ import os
4
+ import typing
5
+
6
+
7
+ def import_modules_in_pkg(pkg: typing.Any) -> None:
8
+ """
9
+ 导入一个包内的所有模块
10
+ Args:
11
+ pkg: 要导入的包对象
12
+ """
13
+ pkg_path = os.path.dirname(pkg.__file__)
14
+ import_dir(pkg_path)
15
+
16
+
17
+ def import_modules_in_pkgs(pkgs: typing.List) -> None:
18
+ for pkg in pkgs:
19
+ import_modules_in_pkg(pkg)
20
+
21
+
22
+ def import_dot_style_dir(dot_sep_path: str):
23
+ sec = dot_sep_path.split(".")
24
+
25
+ return import_dir(os.path.join(*sec))
26
+
27
+
28
+ def import_dir(path: str):
29
+ for file in os.listdir(path):
30
+ if file.endswith(".py") and file != "__init__.py":
31
+ full_path = os.path.join(path, file)
32
+ rel_path = full_path.replace(
33
+ os.path.dirname(os.path.dirname(os.path.dirname(__file__))), ""
34
+ )
35
+ rel_path = rel_path[1:]
36
+ rel_path = rel_path.replace("/", ".")[:-3]
37
+ rel_path = rel_path.replace("\\", ".")
38
+ importlib.import_module(rel_path)
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,30 @@
1
+ Metadata-Version: 2.4
2
+ Name: langbot-plugin
3
+ Version: 0.1.0
4
+ Summary: This package contains the SDK, CLI for building plugins for LangBot, plus the runtime for hosting LangBot plugins
5
+ Author-email: Junyan Qin <rockchinq@gmail.com>
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: mypy>=1.16.0
8
+ Requires-Dist: pydantic>=2.11.5
9
+ Requires-Dist: ruff>=0.11.12
10
+ Requires-Dist: textual>=3.2.0
11
+ Requires-Dist: websockets>=15.0.1
12
+ Description-Content-Type: text/markdown
13
+
14
+ # langbot-plugin-sdk
15
+
16
+ ## Connection
17
+
18
+ ### with LangBot
19
+
20
+ - Stdio
21
+ - Passively
22
+ - WebSocket
23
+ - Server: `:5400 /control/ws`
24
+
25
+ ### with Plugins
26
+
27
+ - Stdio
28
+ - Actively
29
+ - WebSocket (Debug)
30
+ - Server: `:5401 /debug/ws`
@@ -0,0 +1,34 @@
1
+ langbot_plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ langbot_plugin/version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
3
+ langbot_plugin/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ langbot_plugin/cli/__init__.py,sha256=YljXbeWxe1_FMqlfpAJKY7wIht4DNBB5APY6N24wfs8,1214
5
+ langbot_plugin/cli/command.py,sha256=kJhzBn7yiy0qnTWpyzAJ-IVgeyC92y1vy94Jheh5gus,132
6
+ langbot_plugin/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ langbot_plugin/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ langbot_plugin/entities/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ langbot_plugin/entities/io/errors.py,sha256=c0SVQsA2Jbv2hNdqgt2BiqnZ4kgyAMz5gJC1iSb98zE,629
10
+ langbot_plugin/entities/io/req.py,sha256=bnqmdtKGh6zYFopiUt6qJljwjRWrxHNSe2XMcDFA0U8,427
11
+ langbot_plugin/entities/io/resp.py,sha256=ac_0F1k02pxaYH8z1k2WEGt7Hn9CXso7yaAgHNOJTNo,677
12
+ langbot_plugin/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ langbot_plugin/runtime/__main__.py,sha256=d1_jWWW1KdmqloXjKXT-_8nmmIY1j8q49jlzcNLMNSw,198
14
+ langbot_plugin/runtime/app.py,sha256=SyMzhI4uFudS4mjzcoK6Uj1-bYLjpgevT0IY6apHyG0,1691
15
+ langbot_plugin/runtime/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ langbot_plugin/runtime/controller/stdio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ langbot_plugin/runtime/controller/stdio/server.py,sha256=qhLFEvd9h9YPRa2wTtzkTuHF4o_YI3uB7uKcKiGa_L0,704
18
+ langbot_plugin/runtime/controller/ws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ langbot_plugin/runtime/controller/ws/server.py,sha256=f1aptaveyN99Y7xOkQld-RzDOWciq4OV29bJbEXcAQs,2610
20
+ langbot_plugin/runtime/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ langbot_plugin/runtime/io/connection.py,sha256=YGqDJrou55kkkjinlhZGqMi4Hg27eJxqtLU8kWFjRdw,364
22
+ langbot_plugin/runtime/io/handler.py,sha256=R3TKR2ZCutqv8c-LTFY4XfgmitcXjlXVFhGZympIpH4,4723
23
+ langbot_plugin/runtime/io/connections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ langbot_plugin/runtime/io/connections/stdio.py,sha256=VZownx7jCAc6eVn-TY18I8yQjkxeqsdQTrQsLtJr3-E,539
25
+ langbot_plugin/runtime/io/connections/ws.py,sha256=3NTIrlwA8r4VXi5t7StrmKMVjUvsSx3zPJewDTTz-_A,820
26
+ langbot_plugin/runtime/io/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ langbot_plugin/runtime/io/handlers/control.py,sha256=sE4LNwr_sX0lsMgckbGCkWcAK-AEckF0mieloM8h7wI,737
28
+ langbot_plugin/runtime/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ langbot_plugin/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ langbot_plugin/utils/importutil.py,sha256=1FLb67yL12UoOhVOo7rwrNroIkhFkPTqJG4JxuBuWm8,1018
31
+ langbot_plugin-0.1.0.dist-info/METADATA,sha256=BKL2QcTG3PZ0U4klwigV4Ux39BI1mmPEEUN87FUmUBY,664
32
+ langbot_plugin-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
+ langbot_plugin-0.1.0.dist-info/entry_points.txt,sha256=EfG3gGtCzia5YAO0Llvi4YqfaObIw-Kp-CkVqTEYcbE,48
34
+ langbot_plugin-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ lbp = langbot_plugin.cli:main