feat: experimental textual ui
This commit is contained in:
parent
ffcebeb801
commit
96fcfd12e5
5 changed files with 432 additions and 8 deletions
|
|
@ -66,6 +66,8 @@ Python-based Telnet helper for connecting to MUD servers, handling login flows,
|
||||||
|
|
||||||
Add guidance text after the type and optional modifiers separated by `|`, e.g. `#agent intelligent explore carefully|model=mistral/mistral-large-2407|delay=2`. The agent only calls built-in tools (`look`, `move`, `movement`, `explore`, `communication`, `intelligentcommunication`) and refuses unknown names.
|
Add guidance text after the type and optional modifiers separated by `|`, e.g. `#agent intelligent explore carefully|model=mistral/mistral-large-2407|delay=2`. The agent only calls built-in tools (`look`, `move`, `movement`, `explore`, `communication`, `intelligentcommunication`) and refuses unknown names.
|
||||||
|
|
||||||
|
9. Prefer a TUI? Run `python textual_ui.py` to open a two-pane interface (MUD output on the left, agent output on the right) with an input box at the bottom. It accepts the same commands as the CLI (`#execute …`, `#agent …`, or raw MUD commands).
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
All variables can be placed in the `.env` file (one `KEY=value` per line) or provided through the shell environment.
|
All variables can be placed in the `.env` file (one `KEY=value` per line) or provided through the shell environment.
|
||||||
|
|
|
||||||
16
app.py
16
app.py
|
|
@ -7,7 +7,7 @@ from pathlib import Path
|
||||||
from threading import Event, Lock, Thread
|
from threading import Event, Lock, Thread
|
||||||
from typing import Callable, Optional, Type
|
from typing import Callable, Optional, Type
|
||||||
|
|
||||||
from tools import Tool, LookTool
|
from tools import Tool
|
||||||
from agents import Agent, build_agent
|
from agents import Agent, build_agent
|
||||||
from agent_runtime import run_agent
|
from agent_runtime import run_agent
|
||||||
|
|
||||||
|
|
@ -18,6 +18,12 @@ TOOL_REGISTRY = {
|
||||||
"kwargs": {},
|
"kwargs": {},
|
||||||
"description": "Sends the 'schau' look command to refresh the room description.",
|
"description": "Sends the 'schau' look command to refresh the room description.",
|
||||||
},
|
},
|
||||||
|
"simple": {
|
||||||
|
"module": "tools",
|
||||||
|
"class": "LookTool",
|
||||||
|
"kwargs": {},
|
||||||
|
"description": "Alias of 'look'. Sends the 'schau' look command to refresh the room description.",
|
||||||
|
},
|
||||||
"move": {
|
"move": {
|
||||||
"module": "movement_tool",
|
"module": "movement_tool",
|
||||||
"class": "MovementTool",
|
"class": "MovementTool",
|
||||||
|
|
@ -63,6 +69,7 @@ TOOL_REGISTRY = {
|
||||||
TOOL_DESCRIPTIONS = {
|
TOOL_DESCRIPTIONS = {
|
||||||
name: meta["description"] for name, meta in TOOL_REGISTRY.items()
|
name: meta["description"] for name, meta in TOOL_REGISTRY.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
from telnetclient import TelnetClient
|
from telnetclient import TelnetClient
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -208,13 +215,8 @@ def require_env(key: str) -> str:
|
||||||
|
|
||||||
def build_tool(spec: str) -> Tool:
|
def build_tool(spec: str) -> Tool:
|
||||||
"""Instantiate a tool based on configuration."""
|
"""Instantiate a tool based on configuration."""
|
||||||
normalized = spec.strip()
|
normalized = spec.strip() or "look"
|
||||||
if not normalized:
|
|
||||||
return LookTool()
|
|
||||||
|
|
||||||
key = normalized.lower()
|
key = normalized.lower()
|
||||||
if key in {"simple", "look"}:
|
|
||||||
return LookTool()
|
|
||||||
|
|
||||||
if key in TOOL_REGISTRY:
|
if key in TOOL_REGISTRY:
|
||||||
meta = TOOL_REGISTRY[key]
|
meta = TOOL_REGISTRY[key]
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,5 @@ readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"litellm>=1.77.4",
|
"litellm>=1.77.4",
|
||||||
|
"textual>=0.48.1",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
260
textual_ui.py
Normal file
260
textual_ui.py
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
from contextlib import redirect_stdout, redirect_stderr
|
||||||
|
from threading import Event, Thread, current_thread
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from textual.app import App, ComposeResult
|
||||||
|
from textual.containers import Horizontal, Vertical
|
||||||
|
from textual.widgets import Footer, Header, Input, Label, Log
|
||||||
|
|
||||||
|
from app import (
|
||||||
|
TOOL_DESCRIPTIONS,
|
||||||
|
SessionState,
|
||||||
|
build_tool,
|
||||||
|
load_env_file,
|
||||||
|
login,
|
||||||
|
require_env,
|
||||||
|
run_tool_loop,
|
||||||
|
)
|
||||||
|
from agent_runtime import run_agent
|
||||||
|
from agents import build_agent
|
||||||
|
from telnetclient import TelnetClient
|
||||||
|
|
||||||
|
|
||||||
|
class _QueueWriter(io.TextIOBase):
|
||||||
|
def __init__(self, emit: Callable[[str], None]) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._emit = emit
|
||||||
|
self._buffer: str = ""
|
||||||
|
|
||||||
|
def write(self, s: str) -> int: # type: ignore[override]
|
||||||
|
self._buffer += s
|
||||||
|
while "\n" in self._buffer:
|
||||||
|
line, self._buffer = self._buffer.split("\n", 1)
|
||||||
|
if line:
|
||||||
|
self._emit(line)
|
||||||
|
return len(s)
|
||||||
|
|
||||||
|
def flush(self) -> None: # type: ignore[override]
|
||||||
|
if self._buffer:
|
||||||
|
self._emit(self._buffer)
|
||||||
|
self._buffer = ""
|
||||||
|
|
||||||
|
|
||||||
|
class MudUI(App):
|
||||||
|
CSS = """
|
||||||
|
Screen {
|
||||||
|
layout: vertical;
|
||||||
|
}
|
||||||
|
#logs {
|
||||||
|
height: 1fr;
|
||||||
|
}
|
||||||
|
#input-row {
|
||||||
|
padding: 1 2;
|
||||||
|
}
|
||||||
|
Log {
|
||||||
|
border: round #888881;
|
||||||
|
padding: 1 1;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
BINDINGS = [
|
||||||
|
("ctrl+c", "quit", "Quit"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
yield Header(show_clock=True)
|
||||||
|
with Vertical(id="logs"):
|
||||||
|
yield Label("MUD Output")
|
||||||
|
self.mud_log = Log(classes="mud")
|
||||||
|
yield self.mud_log
|
||||||
|
yield Label("Agent Output")
|
||||||
|
self.agent_log = Log(classes="agent")
|
||||||
|
yield self.agent_log
|
||||||
|
with Horizontal(id="input-row"):
|
||||||
|
self.input = Input(placeholder="Type command or #execute/#agent ...", id="command")
|
||||||
|
yield self.input
|
||||||
|
yield Footer()
|
||||||
|
|
||||||
|
def on_mount(self) -> None:
|
||||||
|
self._stop_event = Event()
|
||||||
|
self._ui_thread = current_thread()
|
||||||
|
load_env_file()
|
||||||
|
host = require_env("MISTLE_HOST")
|
||||||
|
port = int(require_env("MISTLE_PORT"))
|
||||||
|
timeout = float(os.environ.get("MISTLE_TIMEOUT", "10"))
|
||||||
|
|
||||||
|
self.state = SessionState()
|
||||||
|
self.client = TelnetClient(host=host, port=port, timeout=timeout)
|
||||||
|
try:
|
||||||
|
self.client.connect()
|
||||||
|
except Exception as exc: # pragma: no cover - network specific
|
||||||
|
self.log_mud(f"[error] Failed to connect: {exc}")
|
||||||
|
return
|
||||||
|
|
||||||
|
writer = _QueueWriter(lambda line: self._emit_to_log(self.mud_log, line))
|
||||||
|
with redirect_stdout(writer), redirect_stderr(writer):
|
||||||
|
login(
|
||||||
|
self.client,
|
||||||
|
user=os.environ.get("MISTLE_USER", ""),
|
||||||
|
password=os.environ.get("MISTLE_PASSWORD", ""),
|
||||||
|
login_prompt=os.environ.get("MISTLE_LOGIN_PROMPT", ""),
|
||||||
|
state=self.state,
|
||||||
|
)
|
||||||
|
writer.flush()
|
||||||
|
|
||||||
|
self.reader_thread = Thread(target=self._reader_loop, daemon=True)
|
||||||
|
self.reader_thread.start()
|
||||||
|
|
||||||
|
self.input.focus()
|
||||||
|
self.log_mud(f"Connected to {host}:{port}")
|
||||||
|
|
||||||
|
def on_input_submitted(self, event: Input.Submitted) -> None:
|
||||||
|
command = event.value.strip()
|
||||||
|
event.input.value = ""
|
||||||
|
if not command:
|
||||||
|
return
|
||||||
|
if command.startswith("#execute"):
|
||||||
|
parts = command.split(maxsplit=1)
|
||||||
|
if len(parts) == 1:
|
||||||
|
self.log_agent("Usage: #execute <tool_spec>")
|
||||||
|
else:
|
||||||
|
self._start_tool(parts[1])
|
||||||
|
return
|
||||||
|
if command.startswith("#agent"):
|
||||||
|
parts = command.split(maxsplit=1)
|
||||||
|
if len(parts) == 1:
|
||||||
|
self.log_agent("Usage: #agent <agent_spec>")
|
||||||
|
else:
|
||||||
|
self._start_agent(parts[1])
|
||||||
|
return
|
||||||
|
self.state.send(self.client, command)
|
||||||
|
self.log_agent(f"> {command}")
|
||||||
|
|
||||||
|
def on_unmount(self) -> None:
|
||||||
|
self._stop_event.set()
|
||||||
|
try:
|
||||||
|
self.client.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _emit_to_log(self, log: Log, message: str) -> None:
|
||||||
|
if current_thread() is self._ui_thread:
|
||||||
|
log.write(message)
|
||||||
|
else:
|
||||||
|
log.write(message)
|
||||||
|
|
||||||
|
def log_mud(self, message: str) -> None:
|
||||||
|
self._emit_to_log(self.mud_log, message)
|
||||||
|
|
||||||
|
def log_agent(self, message: str) -> None:
|
||||||
|
self._emit_to_log(self.agent_log, message)
|
||||||
|
|
||||||
|
def _reader_loop(self) -> None:
|
||||||
|
while not self._stop_event.is_set():
|
||||||
|
data = self.client.receive(timeout=0.3)
|
||||||
|
if data:
|
||||||
|
self.state.update_output(data)
|
||||||
|
self._emit_to_log(self.mud_log, data)
|
||||||
|
|
||||||
|
def _wrap_run(self, func: Callable[[], None]) -> Thread:
|
||||||
|
def runner() -> None:
|
||||||
|
writer = _QueueWriter(lambda line: self._emit_to_log(self.agent_log, line))
|
||||||
|
with redirect_stdout(writer), redirect_stderr(writer):
|
||||||
|
func()
|
||||||
|
writer.flush()
|
||||||
|
|
||||||
|
thread = Thread(target=runner, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
return thread
|
||||||
|
|
||||||
|
def _start_tool(self, raw_spec: str) -> None:
|
||||||
|
spec = raw_spec.strip()
|
||||||
|
if not spec:
|
||||||
|
self.log_agent("Usage: #execute <tool_spec>")
|
||||||
|
return
|
||||||
|
self.log_agent(f"[Tool] Executing {spec!r}")
|
||||||
|
|
||||||
|
def worker() -> None:
|
||||||
|
try:
|
||||||
|
tool = build_tool(spec)
|
||||||
|
except RuntimeError as exc:
|
||||||
|
print(f"[Agent] Failed to load tool {spec}: {exc}")
|
||||||
|
return
|
||||||
|
|
||||||
|
run_tool_loop(
|
||||||
|
self.client,
|
||||||
|
self.state,
|
||||||
|
tool,
|
||||||
|
self._stop_event,
|
||||||
|
min_send_interval=1.0,
|
||||||
|
auto_stop=True,
|
||||||
|
auto_stop_idle=2.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
self._wrap_run(worker)
|
||||||
|
|
||||||
|
def _start_agent(self, raw_spec: str) -> None:
|
||||||
|
spec = raw_spec.strip()
|
||||||
|
if not spec:
|
||||||
|
self.log_agent("Usage: #agent <agent_spec>")
|
||||||
|
return
|
||||||
|
self.log_agent(f"[Agent] Executing {spec!r}")
|
||||||
|
|
||||||
|
def build(spec_str: str) -> Tool:
|
||||||
|
return build_tool(spec_str)
|
||||||
|
|
||||||
|
def run_tool_instance(tool: Tool) -> bool:
|
||||||
|
run_tool_loop(
|
||||||
|
self.client,
|
||||||
|
self.state,
|
||||||
|
tool,
|
||||||
|
self._stop_event,
|
||||||
|
min_send_interval=1.0,
|
||||||
|
auto_stop=True,
|
||||||
|
auto_stop_idle=2.0,
|
||||||
|
)
|
||||||
|
output_after = self.state.snapshot_output()
|
||||||
|
if output_after:
|
||||||
|
observe = getattr(agent, "observe", None)
|
||||||
|
if callable(observe):
|
||||||
|
try:
|
||||||
|
observe(output_after)
|
||||||
|
except Exception as exc: # pragma: no cover
|
||||||
|
print(f"[Agent] observe failed: {exc}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def send_command(command: str) -> None:
|
||||||
|
self.state.send(self.client, command)
|
||||||
|
self._emit_to_log(self.agent_log, f"[Agent] command: {command}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
agent = build_agent(spec, allowed_tools=TOOL_DESCRIPTIONS)
|
||||||
|
except RuntimeError as exc:
|
||||||
|
self.log_agent(f"[Agent] Failed to configure '{spec}': {exc}")
|
||||||
|
return
|
||||||
|
|
||||||
|
last_output = self.state.snapshot_output()
|
||||||
|
observe = getattr(agent, "observe", None)
|
||||||
|
if last_output and callable(observe):
|
||||||
|
try:
|
||||||
|
observe(last_output)
|
||||||
|
except Exception as exc: # pragma: no cover
|
||||||
|
self.log_agent(f"[Agent] observe failed: {exc}")
|
||||||
|
|
||||||
|
self._wrap_run(
|
||||||
|
lambda: run_agent(
|
||||||
|
agent,
|
||||||
|
build_tool=build,
|
||||||
|
run_tool=run_tool_instance,
|
||||||
|
send_command=send_command,
|
||||||
|
stop_event=self._stop_event,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
MudUI().run()
|
||||||
161
uv.lock
generated
161
uv.lock
generated
|
|
@ -725,6 +725,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linkify-it-py"
|
||||||
|
version = "2.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "uc-micro-py" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946, upload-time = "2024-02-04T14:48:04.179Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820, upload-time = "2024-02-04T14:48:02.496Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litellm"
|
name = "litellm"
|
||||||
version = "1.77.4"
|
version = "1.77.4"
|
||||||
|
|
@ -756,6 +768,52 @@ version = "0.7.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/da/eb/95288b1c4aa541eb296a6271e3f8c7ece03b78923ac47dbe95d2287d9f5e/madoka-0.7.1.tar.gz", hash = "sha256:e258baa84fc0a3764365993b8bf5e1b065383a6ca8c9f862fb3e3e709843fae7", size = 81413, upload-time = "2019-02-10T18:38:01.382Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/da/eb/95288b1c4aa541eb296a6271e3f8c7ece03b78923ac47dbe95d2287d9f5e/madoka-0.7.1.tar.gz", hash = "sha256:e258baa84fc0a3764365993b8bf5e1b065383a6ca8c9f862fb3e3e709843fae7", size = 81413, upload-time = "2019-02-10T18:38:01.382Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-py"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version < '3.10'",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mdurl", marker = "python_full_version < '3.10'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
linkify = [
|
||||||
|
{ name = "linkify-it-py", marker = "python_full_version < '3.10'" },
|
||||||
|
]
|
||||||
|
plugins = [
|
||||||
|
{ name = "mdit-py-plugins", version = "0.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-py"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version >= '3.10'",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mdurl", marker = "python_full_version >= '3.10'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
linkify = [
|
||||||
|
{ name = "linkify-it-py", marker = "python_full_version >= '3.10'" },
|
||||||
|
]
|
||||||
|
plugins = [
|
||||||
|
{ name = "mdit-py-plugins", version = "0.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markupsafe"
|
name = "markupsafe"
|
||||||
version = "3.0.2"
|
version = "3.0.2"
|
||||||
|
|
@ -824,16 +882,59 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506, upload-time = "2024-10-18T15:21:52.974Z" },
|
{ url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506, upload-time = "2024-10-18T15:21:52.974Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdit-py-plugins"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version < '3.10'",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542, upload-time = "2024-09-09T20:27:49.564Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316, upload-time = "2024-09-09T20:27:48.397Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdit-py-plugins"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
resolution-markers = [
|
||||||
|
"python_full_version >= '3.10'",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdurl"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mistle-mudbot"
|
name = "mistle-mudbot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "litellm" },
|
{ name = "litellm" },
|
||||||
|
{ name = "textual" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "litellm", specifier = ">=1.77.4" }]
|
requires-dist = [
|
||||||
|
{ name = "litellm", specifier = ">=1.77.4" },
|
||||||
|
{ name = "textual", specifier = ">=0.48.1" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multidict"
|
name = "multidict"
|
||||||
|
|
@ -983,6 +1084,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "4.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pondpond"
|
name = "pondpond"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
|
@ -1224,6 +1334,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" },
|
{ url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.19.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|
@ -1457,6 +1576,20 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rich"
|
||||||
|
version = "14.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||||
|
{ name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rpds-py"
|
name = "rpds-py"
|
||||||
version = "0.27.1"
|
version = "0.27.1"
|
||||||
|
|
@ -1628,6 +1761,23 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textual"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, extra = ["linkify", "plugins"], marker = "python_full_version < '3.10'" },
|
||||||
|
{ name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, extra = ["linkify", "plugins"], marker = "python_full_version >= '3.10'" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
{ name = "rich" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/da/44/4b524b2f06e0fa6c4ede56a4e9af5edd5f3f83cf2eea5cb4fd0ce5bbe063/textual-6.1.0.tar.gz", hash = "sha256:cc89826ca2146c645563259320ca4ddc75d183c77afb7d58acdd46849df9144d", size = 1564786, upload-time = "2025-09-02T11:42:34.655Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/43/f91e041f239b54399310a99041faf33beae9a6e628671471d0fcd6276af4/textual-6.1.0-py3-none-any.whl", hash = "sha256:a3f5e6710404fcdc6385385db894699282dccf2ad50103cebc677403c1baadd5", size = 707840, upload-time = "2025-09-02T11:42:32.746Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiktoken"
|
name = "tiktoken"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
@ -1728,6 +1878,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
|
{ url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uc-micro-py"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043, upload-time = "2024-02-09T16:52:01.654Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229, upload-time = "2024-02-09T16:52:00.371Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue