flowly-code 1.0.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.
- flowly_code/__init__.py +30 -0
- flowly_code/__main__.py +8 -0
- flowly_code/activity/__init__.py +1 -0
- flowly_code/activity/bus.py +91 -0
- flowly_code/activity/events.py +40 -0
- flowly_code/agent/__init__.py +8 -0
- flowly_code/agent/context.py +485 -0
- flowly_code/agent/loop.py +1349 -0
- flowly_code/agent/memory.py +109 -0
- flowly_code/agent/skills.py +259 -0
- flowly_code/agent/subagent.py +249 -0
- flowly_code/agent/tools/__init__.py +6 -0
- flowly_code/agent/tools/base.py +55 -0
- flowly_code/agent/tools/delegate.py +194 -0
- flowly_code/agent/tools/dispatch.py +840 -0
- flowly_code/agent/tools/docker.py +609 -0
- flowly_code/agent/tools/filesystem.py +280 -0
- flowly_code/agent/tools/mcp.py +85 -0
- flowly_code/agent/tools/message.py +235 -0
- flowly_code/agent/tools/registry.py +257 -0
- flowly_code/agent/tools/screenshot.py +444 -0
- flowly_code/agent/tools/shell.py +166 -0
- flowly_code/agent/tools/spawn.py +65 -0
- flowly_code/agent/tools/system.py +917 -0
- flowly_code/agent/tools/trello.py +420 -0
- flowly_code/agent/tools/web.py +139 -0
- flowly_code/agent/tools/x.py +399 -0
- flowly_code/bus/__init__.py +6 -0
- flowly_code/bus/events.py +37 -0
- flowly_code/bus/queue.py +81 -0
- flowly_code/channels/__init__.py +6 -0
- flowly_code/channels/base.py +121 -0
- flowly_code/channels/manager.py +135 -0
- flowly_code/channels/telegram.py +1132 -0
- flowly_code/cli/__init__.py +1 -0
- flowly_code/cli/commands.py +1831 -0
- flowly_code/cli/setup.py +1356 -0
- flowly_code/compaction/__init__.py +39 -0
- flowly_code/compaction/estimator.py +88 -0
- flowly_code/compaction/pruning.py +223 -0
- flowly_code/compaction/service.py +297 -0
- flowly_code/compaction/summarizer.py +384 -0
- flowly_code/compaction/types.py +71 -0
- flowly_code/config/__init__.py +6 -0
- flowly_code/config/loader.py +102 -0
- flowly_code/config/schema.py +324 -0
- flowly_code/exec/__init__.py +39 -0
- flowly_code/exec/approvals.py +288 -0
- flowly_code/exec/executor.py +184 -0
- flowly_code/exec/safety.py +247 -0
- flowly_code/exec/types.py +88 -0
- flowly_code/gateway/__init__.py +5 -0
- flowly_code/gateway/server.py +103 -0
- flowly_code/heartbeat/__init__.py +5 -0
- flowly_code/heartbeat/service.py +130 -0
- flowly_code/multiagent/README.md +248 -0
- flowly_code/multiagent/__init__.py +1 -0
- flowly_code/multiagent/invoke.py +210 -0
- flowly_code/multiagent/orchestrator.py +156 -0
- flowly_code/multiagent/router.py +156 -0
- flowly_code/multiagent/setup.py +171 -0
- flowly_code/pairing/__init__.py +21 -0
- flowly_code/pairing/store.py +343 -0
- flowly_code/providers/__init__.py +6 -0
- flowly_code/providers/base.py +69 -0
- flowly_code/providers/litellm_provider.py +178 -0
- flowly_code/providers/transcription.py +64 -0
- flowly_code/session/__init__.py +5 -0
- flowly_code/session/manager.py +249 -0
- flowly_code/skills/README.md +24 -0
- flowly_code/skills/compact/SKILL.md +27 -0
- flowly_code/skills/github/SKILL.md +48 -0
- flowly_code/skills/skill-creator/SKILL.md +371 -0
- flowly_code/skills/summarize/SKILL.md +67 -0
- flowly_code/skills/tmux/SKILL.md +121 -0
- flowly_code/skills/tmux/scripts/find-sessions.sh +112 -0
- flowly_code/skills/tmux/scripts/wait-for-text.sh +83 -0
- flowly_code/skills/weather/SKILL.md +49 -0
- flowly_code/utils/__init__.py +5 -0
- flowly_code/utils/helpers.py +91 -0
- flowly_code-1.0.0.dist-info/METADATA +724 -0
- flowly_code-1.0.0.dist-info/RECORD +86 -0
- flowly_code-1.0.0.dist-info/WHEEL +4 -0
- flowly_code-1.0.0.dist-info/entry_points.txt +2 -0
- flowly_code-1.0.0.dist-info/licenses/LICENSE +191 -0
- flowly_code-1.0.0.dist-info/licenses/NOTICE +74 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Channel manager for coordinating chat channels."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from loguru import logger
|
|
7
|
+
|
|
8
|
+
from flowly_code.bus.events import OutboundMessage
|
|
9
|
+
from flowly_code.bus.queue import MessageBus
|
|
10
|
+
from flowly_code.channels.base import BaseChannel
|
|
11
|
+
from flowly_code.config.schema import Config
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ChannelManager:
|
|
15
|
+
"""
|
|
16
|
+
Manages chat channels and coordinates message routing.
|
|
17
|
+
|
|
18
|
+
Responsibilities:
|
|
19
|
+
- Initialize enabled channels (Telegram, WhatsApp, etc.)
|
|
20
|
+
- Start/stop channels
|
|
21
|
+
- Route outbound messages
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, config: Config, bus: MessageBus):
|
|
25
|
+
self.config = config
|
|
26
|
+
self.bus = bus
|
|
27
|
+
self.channels: dict[str, BaseChannel] = {}
|
|
28
|
+
self._dispatch_task: asyncio.Task | None = None
|
|
29
|
+
|
|
30
|
+
self._init_channels()
|
|
31
|
+
|
|
32
|
+
def _init_channels(self) -> None:
|
|
33
|
+
"""Initialize channels based on config."""
|
|
34
|
+
|
|
35
|
+
# Telegram channel
|
|
36
|
+
if self.config.channels.telegram.enabled:
|
|
37
|
+
try:
|
|
38
|
+
from flowly_code.channels.telegram import TelegramChannel
|
|
39
|
+
self.channels["telegram"] = TelegramChannel(
|
|
40
|
+
self.config.channels.telegram,
|
|
41
|
+
self.bus,
|
|
42
|
+
groq_api_key=self.config.providers.groq.api_key,
|
|
43
|
+
dispatch_config=self.config.integrations.dispatch,
|
|
44
|
+
)
|
|
45
|
+
logger.info("Telegram channel enabled")
|
|
46
|
+
except ImportError as e:
|
|
47
|
+
logger.warning(f"Telegram channel not available: {e}")
|
|
48
|
+
|
|
49
|
+
async def start_all(self) -> None:
|
|
50
|
+
"""Start all channels and the outbound dispatcher."""
|
|
51
|
+
if not self.channels:
|
|
52
|
+
logger.warning("No channels enabled")
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
# Start outbound dispatcher
|
|
56
|
+
self._dispatch_task = asyncio.create_task(self._dispatch_outbound())
|
|
57
|
+
|
|
58
|
+
# Start channels
|
|
59
|
+
tasks = []
|
|
60
|
+
for name, channel in self.channels.items():
|
|
61
|
+
logger.info(f"Starting {name} channel...")
|
|
62
|
+
tasks.append(asyncio.create_task(channel.start()))
|
|
63
|
+
|
|
64
|
+
# Wait for all to complete (they should run forever)
|
|
65
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
66
|
+
|
|
67
|
+
async def stop_all(self) -> None:
|
|
68
|
+
"""Stop all channels and the dispatcher."""
|
|
69
|
+
logger.info("Stopping all channels...")
|
|
70
|
+
|
|
71
|
+
# Stop dispatcher
|
|
72
|
+
if self._dispatch_task:
|
|
73
|
+
self._dispatch_task.cancel()
|
|
74
|
+
try:
|
|
75
|
+
await self._dispatch_task
|
|
76
|
+
except asyncio.CancelledError:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
# Stop all channels
|
|
80
|
+
for name, channel in self.channels.items():
|
|
81
|
+
try:
|
|
82
|
+
await channel.stop()
|
|
83
|
+
logger.info(f"Stopped {name} channel")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.error(f"Error stopping {name}: {e}")
|
|
86
|
+
|
|
87
|
+
async def _dispatch_outbound(self) -> None:
|
|
88
|
+
"""Dispatch outbound messages to the appropriate channel."""
|
|
89
|
+
logger.info("Outbound dispatcher started")
|
|
90
|
+
|
|
91
|
+
while True:
|
|
92
|
+
try:
|
|
93
|
+
msg = await asyncio.wait_for(
|
|
94
|
+
self.bus.consume_outbound(),
|
|
95
|
+
timeout=1.0
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
channel = self.channels.get(msg.channel)
|
|
99
|
+
if channel:
|
|
100
|
+
try:
|
|
101
|
+
await channel.send(msg)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Error sending to {msg.channel}: {e}")
|
|
104
|
+
else:
|
|
105
|
+
logger.warning(f"Unknown channel: {msg.channel}")
|
|
106
|
+
|
|
107
|
+
except asyncio.TimeoutError:
|
|
108
|
+
continue
|
|
109
|
+
except asyncio.CancelledError:
|
|
110
|
+
break
|
|
111
|
+
|
|
112
|
+
def get_channel(self, name: str) -> BaseChannel | None:
|
|
113
|
+
"""Get a channel by name."""
|
|
114
|
+
return self.channels.get(name)
|
|
115
|
+
|
|
116
|
+
def set_compact_callback(self, callback: callable) -> None:
|
|
117
|
+
"""Set the compaction callback for all channels that support it."""
|
|
118
|
+
for channel in self.channels.values():
|
|
119
|
+
if hasattr(channel, "set_compact_callback"):
|
|
120
|
+
channel.set_compact_callback(callback)
|
|
121
|
+
|
|
122
|
+
def get_status(self) -> dict[str, Any]:
|
|
123
|
+
"""Get status of all channels."""
|
|
124
|
+
return {
|
|
125
|
+
name: {
|
|
126
|
+
"enabled": True,
|
|
127
|
+
"running": channel.is_running
|
|
128
|
+
}
|
|
129
|
+
for name, channel in self.channels.items()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def enabled_channels(self) -> list[str]:
|
|
134
|
+
"""Get list of enabled channel names."""
|
|
135
|
+
return list(self.channels.keys())
|