federaide-dev-nightly 2.0.8__tar.gz → 2.1.2__tar.gz
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.
- {federaide_dev_nightly-2.0.8/src/federaide_dev_nightly.egg-info → federaide_dev_nightly-2.1.2}/PKG-INFO +3 -2
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/pyproject.toml +4 -3
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2/src/federaide_dev_nightly.egg-info}/PKG-INFO +3 -2
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federaide_dev_nightly.egg-info/SOURCES.txt +2 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federaide_dev_nightly.egg-info/requires.txt +2 -1
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/agent.py +381 -29
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/agent_core.py +1 -1
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/chatgpt_auth.py +2 -4
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/commands.py +17 -0
- federaide_dev_nightly-2.1.2/src/federate/git_auth.py +400 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/mcp_handler.py +1 -1
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/orchestration.py +26 -2
- federaide_dev_nightly-2.1.2/src/federate/team_mesh.py +544 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/toolbox.py +58 -35
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/LICENSE +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/MANIFEST.in +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/README.md +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/go/cmd/bridge/main.go +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/go/cmd/embed/main.go +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/go/cmd/search/main.go +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/go/go.mod +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/go/go.sum +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/scripts/build_go.sh +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/setup.cfg +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/setup.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federaide_dev_nightly.egg-info/dependency_links.txt +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federaide_dev_nightly.egg-info/entry_points.txt +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federaide_dev_nightly.egg-info/top_level.txt +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/__init__.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/__main__.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/app.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/audio_handler.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/execution.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/semantic_search.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/styles/fonts/Michroma-Regular.ttf +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/styles/fonts/SpaceGrotesk-Bold.ttf +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/styles/fonts/SpaceGrotesk-VariableFont_wght.ttf +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/styles/style.css +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/subagents.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/telegram_handler.py +0 -0
- {federaide_dev_nightly-2.0.8 → federaide_dev_nightly-2.1.2}/src/federate/textIDE.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: federaide-dev-nightly
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: A cross-platform terminal based p2p agent orchestration harness and universal automation system
|
|
5
5
|
Author-email: ROCK-LAB-PRIVATE-LIMITED <arkadeep_ghosh@rocklab.in>
|
|
6
6
|
License: GNU Affero General Public License v3
|
|
@@ -51,6 +51,7 @@ Requires-Dist: orjson==3.12.0
|
|
|
51
51
|
Requires-Dist: cryptography==50.0.1
|
|
52
52
|
Requires-Dist: ormsgpack==1.12.2
|
|
53
53
|
Requires-Dist: rpds-py==2026.6.3
|
|
54
|
+
Requires-Dist: uuid-utils==0.17.1
|
|
54
55
|
Requires-Dist: pywinpty; platform_system == "Windows"
|
|
55
56
|
Provides-Extra: audio
|
|
56
57
|
Requires-Dist: sounddevice; extra == "audio"
|
|
@@ -58,7 +59,7 @@ Requires-Dist: kokoro-onnx; extra == "audio"
|
|
|
58
59
|
Requires-Dist: sherpa-onnx; extra == "audio"
|
|
59
60
|
Provides-Extra: vision
|
|
60
61
|
Requires-Dist: pyautogui; extra == "vision"
|
|
61
|
-
Requires-Dist: pillow; extra == "vision"
|
|
62
|
+
Requires-Dist: pillow==12.3.0; extra == "vision"
|
|
62
63
|
Provides-Extra: pdf
|
|
63
64
|
Requires-Dist: weasyprint; extra == "pdf"
|
|
64
65
|
Requires-Dist: pypdf; extra == "pdf"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "federaide-dev-nightly"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.1.2"
|
|
8
8
|
description = "A cross-platform terminal based p2p agent orchestration harness and universal automation system"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "GNU Affero General Public License v3"}
|
|
@@ -57,6 +57,7 @@ dependencies = [
|
|
|
57
57
|
"cryptography==50.0.1",
|
|
58
58
|
"ormsgpack==1.12.2",
|
|
59
59
|
"rpds-py==2026.6.3",
|
|
60
|
+
"uuid-utils==0.17.1",
|
|
60
61
|
# Platform-specific hard dependencies
|
|
61
62
|
"pywinpty; platform_system == 'Windows'",
|
|
62
63
|
]
|
|
@@ -71,7 +72,7 @@ audio = [
|
|
|
71
72
|
# Autonomous Visual Computer Use / Computer Vision (optional)
|
|
72
73
|
vision = [
|
|
73
74
|
"pyautogui",
|
|
74
|
-
"pillow",
|
|
75
|
+
"pillow==12.3.0",
|
|
75
76
|
]
|
|
76
77
|
# PDF report generation for Deep Research (optional)
|
|
77
78
|
pdf = [
|
|
@@ -108,4 +109,4 @@ Issues = "https://github.com/ROCK-LAB-PRIVATE-LIMITED/federaide/issues"
|
|
|
108
109
|
where = ["src"]
|
|
109
110
|
|
|
110
111
|
[tool.setuptools.package-data]
|
|
111
|
-
federate = ["bin/*", "styles/*", "styles/fonts/*"]
|
|
112
|
+
federate = ["bin/*", "styles/*", "styles/fonts/*"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: federaide-dev-nightly
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: A cross-platform terminal based p2p agent orchestration harness and universal automation system
|
|
5
5
|
Author-email: ROCK-LAB-PRIVATE-LIMITED <arkadeep_ghosh@rocklab.in>
|
|
6
6
|
License: GNU Affero General Public License v3
|
|
@@ -51,6 +51,7 @@ Requires-Dist: orjson==3.12.0
|
|
|
51
51
|
Requires-Dist: cryptography==50.0.1
|
|
52
52
|
Requires-Dist: ormsgpack==1.12.2
|
|
53
53
|
Requires-Dist: rpds-py==2026.6.3
|
|
54
|
+
Requires-Dist: uuid-utils==0.17.1
|
|
54
55
|
Requires-Dist: pywinpty; platform_system == "Windows"
|
|
55
56
|
Provides-Extra: audio
|
|
56
57
|
Requires-Dist: sounddevice; extra == "audio"
|
|
@@ -58,7 +59,7 @@ Requires-Dist: kokoro-onnx; extra == "audio"
|
|
|
58
59
|
Requires-Dist: sherpa-onnx; extra == "audio"
|
|
59
60
|
Provides-Extra: vision
|
|
60
61
|
Requires-Dist: pyautogui; extra == "vision"
|
|
61
|
-
Requires-Dist: pillow; extra == "vision"
|
|
62
|
+
Requires-Dist: pillow==12.3.0; extra == "vision"
|
|
62
63
|
Provides-Extra: pdf
|
|
63
64
|
Requires-Dist: weasyprint; extra == "pdf"
|
|
64
65
|
Requires-Dist: pypdf; extra == "pdf"
|
|
@@ -24,10 +24,12 @@ src/federate/audio_handler.py
|
|
|
24
24
|
src/federate/chatgpt_auth.py
|
|
25
25
|
src/federate/commands.py
|
|
26
26
|
src/federate/execution.py
|
|
27
|
+
src/federate/git_auth.py
|
|
27
28
|
src/federate/mcp_handler.py
|
|
28
29
|
src/federate/orchestration.py
|
|
29
30
|
src/federate/semantic_search.py
|
|
30
31
|
src/federate/subagents.py
|
|
32
|
+
src/federate/team_mesh.py
|
|
31
33
|
src/federate/telegram_handler.py
|
|
32
34
|
src/federate/textIDE.py
|
|
33
35
|
src/federate/toolbox.py
|
|
@@ -1732,6 +1732,44 @@ class GitConflictModal(ModalScreen[str]):
|
|
|
1732
1732
|
else:
|
|
1733
1733
|
self.dismiss("abort")
|
|
1734
1734
|
|
|
1735
|
+
class MeshSeedModal(ModalScreen[str]):
|
|
1736
|
+
DEFAULT_CSS = """
|
|
1737
|
+
MeshSeedModal { align: center middle; background: $background 60%; }
|
|
1738
|
+
#seed_dialog { width: 75; height: auto; border: thick $primary; background: $surface; padding: 1 2; }
|
|
1739
|
+
#seed_input { margin-top: 1; margin-bottom: 1; height: auto; min-height: 4; max-height: 8; }
|
|
1740
|
+
.seed_help { color: $text-muted; margin-top: 0; margin-bottom: 1; text-wrap: wrap; height: auto; }
|
|
1741
|
+
.seed_buttons { layout: horizontal; height: auto; align: right middle; margin-top: 1; }
|
|
1742
|
+
.seed_buttons Button { margin-left: 1; }
|
|
1743
|
+
"""
|
|
1744
|
+
|
|
1745
|
+
def __init__(self, current_seed: str = ""):
|
|
1746
|
+
super().__init__()
|
|
1747
|
+
self.current_seed = current_seed
|
|
1748
|
+
|
|
1749
|
+
def compose(self) -> ComposeResult:
|
|
1750
|
+
with Vertical(id="seed_dialog"):
|
|
1751
|
+
yield Label(" Mesh Master Seed Phrase", classes="pane_title")
|
|
1752
|
+
yield Label(
|
|
1753
|
+
"Enter your seed phrase or secret passphrase to synchronize identity and encryption keys across all your devices:",
|
|
1754
|
+
classes="seed_help"
|
|
1755
|
+
)
|
|
1756
|
+
yield TextArea(self.current_seed, id="seed_input", show_line_numbers=False)
|
|
1757
|
+
with Horizontal(classes="seed_buttons"):
|
|
1758
|
+
yield Button("Save Seed", id="btn_save_seed", variant="success")
|
|
1759
|
+
yield Button("Cancel", id="btn_cancel_seed", variant="error")
|
|
1760
|
+
|
|
1761
|
+
def on_mount(self):
|
|
1762
|
+
self.query_one("#seed_input", TextArea).focus()
|
|
1763
|
+
|
|
1764
|
+
@on(Button.Pressed, "#btn_save_seed")
|
|
1765
|
+
def on_save(self):
|
|
1766
|
+
val = self.query_one("#seed_input", TextArea).text.strip()
|
|
1767
|
+
self.dismiss(val)
|
|
1768
|
+
|
|
1769
|
+
@on(Button.Pressed, "#btn_cancel_seed")
|
|
1770
|
+
def on_cancel(self):
|
|
1771
|
+
self.dismiss(None)
|
|
1772
|
+
|
|
1735
1773
|
class TeamsModal(ModalScreen[None]):
|
|
1736
1774
|
DEFAULT_CSS = """
|
|
1737
1775
|
TeamsModal { align: center middle; background: $background 60%; }
|
|
@@ -1748,8 +1786,15 @@ class TeamsModal(ModalScreen[None]):
|
|
|
1748
1786
|
#team_folder_input { width: 1fr; }
|
|
1749
1787
|
#team_git_user_input { width: 1fr; margin-right: 1; }
|
|
1750
1788
|
#team_git_pat_input { width: 1fr; }
|
|
1751
|
-
.team_form_row { layout: horizontal; height:
|
|
1752
|
-
.team_form_row Button { width: 1fr; margin: 0 1; }
|
|
1789
|
+
.team_form_row { layout: horizontal; height: 3; margin-top: 1; width: 100%; }
|
|
1790
|
+
.team_form_row Button { width: 1fr; margin: 0 1; height: 3; }
|
|
1791
|
+
#team_readme_input { height: 8; min-height: 5; border: round $accent; background: $surface; margin-top: 1; margin-bottom: 1; }
|
|
1792
|
+
#mesh_relay_url_input { margin-top: 1; margin-bottom: 0; }
|
|
1793
|
+
#mesh_relay_user_input { width: 1fr; margin-right: 1; }
|
|
1794
|
+
#mesh_relay_pat_input { width: 1fr; }
|
|
1795
|
+
#mesh_seed_btn { width: 100%; height: 3; margin-top: 1; margin-bottom: 1; }
|
|
1796
|
+
#channel_peers_display { border: round $accent; background: $surface; padding: 1; margin-top: 1; margin-bottom: 1; min-height: 3; }
|
|
1797
|
+
#sync_channel_btn { width: 100%; height: 3; margin-bottom: 1; }
|
|
1753
1798
|
#teams_bottom_buttons { height: auto; align: right middle; margin-top: 0; }
|
|
1754
1799
|
#teams_bottom_buttons Button { margin-left: 1; }
|
|
1755
1800
|
"""
|
|
@@ -1784,6 +1829,20 @@ class TeamsModal(ModalScreen[None]):
|
|
|
1784
1829
|
yield Button("Pull", id="pull_btn", variant="warning")
|
|
1785
1830
|
yield Button("Push", id="push_btn", variant="warning")
|
|
1786
1831
|
yield Button("Sync", id="sync_now_btn", variant="warning")
|
|
1832
|
+
|
|
1833
|
+
yield Label("Team Charter (README.md - Injected into all agents):", classes="section_label")
|
|
1834
|
+
yield TextArea(id="team_readme_input", show_line_numbers=False, soft_wrap=True)
|
|
1835
|
+
|
|
1836
|
+
yield Label("Channel Relay Repository (Team-Specific Coordination Channel):", classes="section_label")
|
|
1837
|
+
yield Input(placeholder="Channel Relay Repo URL (e.g. https://github.com/user/fed-relay-a.git)", id="mesh_relay_url_input")
|
|
1838
|
+
with Horizontal(classes="form_row"):
|
|
1839
|
+
yield Input(placeholder="Channel Git Username", id="mesh_relay_user_input")
|
|
1840
|
+
yield Input(placeholder="Channel Git PAT", id="mesh_relay_pat_input", password=True)
|
|
1841
|
+
yield Button("Configure Channel PSK Seed Phrase", id="mesh_seed_btn", variant="primary")
|
|
1842
|
+
|
|
1843
|
+
yield Label("Autodetected Channel Peers (via Relay):", classes="section_label")
|
|
1844
|
+
yield Static(id="channel_peers_display")
|
|
1845
|
+
yield Button("Sync Channel & Refresh Peers", id="sync_channel_btn", variant="primary")
|
|
1787
1846
|
|
|
1788
1847
|
yield Label("Registered Teams:", classes="section_label")
|
|
1789
1848
|
yield Vertical(id="team_list")
|
|
@@ -1810,8 +1869,39 @@ class TeamsModal(ModalScreen[None]):
|
|
|
1810
1869
|
self.query_one("#team_remote_url_input", Input).value = remote_url
|
|
1811
1870
|
self.query_one("#team_git_user_input", Input).value = git_user
|
|
1812
1871
|
self.query_one("#team_git_pat_input", Input).value = git_pat
|
|
1872
|
+
readme_path = os.path.join(self.editing_path, "README.md")
|
|
1873
|
+
readme_text = ""
|
|
1874
|
+
if os.path.exists(readme_path):
|
|
1875
|
+
try:
|
|
1876
|
+
with open(readme_path, "r", encoding="utf-8") as f:
|
|
1877
|
+
readme_text = f.read()
|
|
1878
|
+
except Exception: pass
|
|
1879
|
+
self.query_one("#team_readme_input", TextArea).text = readme_text
|
|
1880
|
+
|
|
1881
|
+
import team_mesh
|
|
1882
|
+
r_url, r_user, r_pat = team_mesh.get_relay_credentials(self.editing_path)
|
|
1883
|
+
self.query_one("#mesh_relay_url_input", Input).value = r_url
|
|
1884
|
+
self.query_one("#mesh_relay_user_input", Input).value = r_user
|
|
1885
|
+
self.query_one("#mesh_relay_pat_input", Input).value = r_pat
|
|
1886
|
+
self.refresh_channel_peers_ui(self.editing_path)
|
|
1813
1887
|
self.query_one("#save_team_btn", Button).label = "Update Team"
|
|
1814
1888
|
|
|
1889
|
+
def refresh_channel_peers_ui(self, t_path: str = None):
|
|
1890
|
+
if not self.is_mounted:
|
|
1891
|
+
return
|
|
1892
|
+
target = t_path or self.editing_path or toolbox.get_team_dir()
|
|
1893
|
+
import team_mesh
|
|
1894
|
+
peers = team_mesh.discover_peer_teams(target)
|
|
1895
|
+
try:
|
|
1896
|
+
display = self.query_one("#channel_peers_display", Static)
|
|
1897
|
+
if peers:
|
|
1898
|
+
lines = [f"[bold green]● {name}[/bold green]: [dim]{desc[:120]}{'...' if len(desc)>120 else ''}[/dim]" for name, desc in peers.items()]
|
|
1899
|
+
display.update("\n".join(lines))
|
|
1900
|
+
else:
|
|
1901
|
+
display.update("[dim]No peer teams detected on this channel yet. (Click 'Sync Channel & Refresh Peers')[/dim]")
|
|
1902
|
+
except Exception:
|
|
1903
|
+
pass
|
|
1904
|
+
|
|
1815
1905
|
def clear_form(self):
|
|
1816
1906
|
self.editing_path = None
|
|
1817
1907
|
self.query_one("#form_header_label", Label).update("Create New Team Workspace:")
|
|
@@ -1820,8 +1910,12 @@ class TeamsModal(ModalScreen[None]):
|
|
|
1820
1910
|
self.query_one("#team_remote_url_input", Input).value = ""
|
|
1821
1911
|
self.query_one("#team_git_user_input", Input).value = ""
|
|
1822
1912
|
self.query_one("#team_git_pat_input", Input).value = ""
|
|
1913
|
+
self.query_one("#team_readme_input", TextArea).text = ""
|
|
1914
|
+
self.query_one("#mesh_relay_url_input", Input).value = ""
|
|
1915
|
+
self.query_one("#mesh_relay_user_input", Input).value = ""
|
|
1916
|
+
self.query_one("#mesh_relay_pat_input", Input).value = ""
|
|
1917
|
+
self.query_one("#channel_peers_display", Static).update("[dim]Save team to connect to channel.[/dim]")
|
|
1823
1918
|
self.query_one("#save_team_btn", Button).label = "Save Team"
|
|
1824
|
-
|
|
1825
1919
|
def _handle_git_action(self, action_name: str, target_team_dir: str):
|
|
1826
1920
|
def _run_action():
|
|
1827
1921
|
try:
|
|
@@ -1945,37 +2039,17 @@ class TeamsModal(ModalScreen[None]):
|
|
|
1945
2039
|
def _run_restore():
|
|
1946
2040
|
try:
|
|
1947
2041
|
from urllib.parse import urlparse, urlunparse, quote
|
|
1948
|
-
import subprocess,
|
|
1949
|
-
|
|
1950
|
-
@contextlib.contextmanager
|
|
1951
|
-
def git_askpass_context(pat_str: str):
|
|
1952
|
-
askpass_ext = ".bat" if os.name == "nt" else ".sh"
|
|
1953
|
-
fd, askpass_path = tempfile.mkstemp(suffix=askpass_ext, text=True)
|
|
1954
|
-
with os.fdopen(fd, "w") as f:
|
|
1955
|
-
if os.name == "nt":
|
|
1956
|
-
f.write("@echo off\nif \"%~1\"==\"\" exit /b 0\necho %FEDERAIDE_GIT_PASSWORD%\n")
|
|
1957
|
-
else:
|
|
1958
|
-
f.write("#!/bin/sh\necho \"$FEDERAIDE_GIT_PASSWORD\"\n")
|
|
1959
|
-
if os.name != "nt":
|
|
1960
|
-
os.chmod(askpass_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
|
1961
|
-
|
|
1962
|
-
env = os.environ.copy()
|
|
1963
|
-
env["GIT_ASKPASS"] = askpass_path
|
|
1964
|
-
env["FEDERAIDE_GIT_PASSWORD"] = pat_str
|
|
1965
|
-
env["GIT_TERMINAL_PROMPT"] = "0"
|
|
1966
|
-
try:
|
|
1967
|
-
yield env
|
|
1968
|
-
finally:
|
|
1969
|
-
try: os.remove(askpass_path)
|
|
1970
|
-
except Exception: pass
|
|
2042
|
+
import subprocess, os
|
|
2043
|
+
from git_auth import git_askpass_context
|
|
1971
2044
|
|
|
1972
2045
|
parsed = urlparse(url)
|
|
1973
2046
|
user_part = quote(user, safe='') if user else "git"
|
|
1974
|
-
|
|
2047
|
+
host = parsed.netloc.split("@")[-1]
|
|
2048
|
+
auth_netloc = f"{user_part}@{host}"
|
|
1975
2049
|
safe_url = urlunparse((parsed.scheme, auth_netloc, parsed.path, parsed.params, parsed.query, parsed.fragment))
|
|
1976
2050
|
|
|
1977
2051
|
with git_askpass_context(pat) as env:
|
|
1978
|
-
res = subprocess.run(["git", "clone", safe_url, target_path], capture_output=True, text=True, env=env)
|
|
2052
|
+
res = subprocess.run(["git", "-c", "credential.helper=", "clone", safe_url, target_path], capture_output=True, text=True, env=env)
|
|
1979
2053
|
|
|
1980
2054
|
if res.returncode == 0:
|
|
1981
2055
|
subprocess.run(["git", "remote", "set-url", "origin", url], cwd=target_path, capture_output=True)
|
|
@@ -2003,7 +2077,6 @@ class TeamsModal(ModalScreen[None]):
|
|
|
2003
2077
|
pass
|
|
2004
2078
|
self.app.call_from_thread(_reenable)
|
|
2005
2079
|
|
|
2006
|
-
import threading
|
|
2007
2080
|
threading.Thread(target=_run_restore, daemon=True).start()
|
|
2008
2081
|
|
|
2009
2082
|
elif btn_id in ("sync_now_btn", "pull_btn", "push_btn"):
|
|
@@ -2019,7 +2092,77 @@ class TeamsModal(ModalScreen[None]):
|
|
|
2019
2092
|
self.notify(f"{action.title()}ing with Git remote for '{os.path.basename(target_team_dir)}'...", severity="information")
|
|
2020
2093
|
self._handle_git_action(action, target_team_dir)
|
|
2021
2094
|
|
|
2095
|
+
elif btn_id == "sync_channel_btn":
|
|
2096
|
+
target = self.editing_path or toolbox.get_team_dir()
|
|
2097
|
+
import team_mesh
|
|
2098
|
+
r_url = self.query_one("#mesh_relay_url_input", Input).value.strip()
|
|
2099
|
+
r_user = self.query_one("#mesh_relay_user_input", Input).value.strip()
|
|
2100
|
+
r_pat = self.query_one("#mesh_relay_pat_input", Input).value.strip()
|
|
2101
|
+
if not r_url or not r_pat:
|
|
2102
|
+
self.notify("Please enter the Channel Relay Repo URL and PAT first.", severity="error")
|
|
2103
|
+
return
|
|
2104
|
+
|
|
2105
|
+
# Save channel credentials immediately from inputs
|
|
2106
|
+
team_mesh.save_relay_credentials(url=r_url, user=r_user, pat=r_pat, team_dir=target)
|
|
2107
|
+
|
|
2108
|
+
readme_text = self.query_one("#team_readme_input", TextArea).text
|
|
2109
|
+
if readme_text:
|
|
2110
|
+
try:
|
|
2111
|
+
with open(os.path.join(target, "README.md"), "w", encoding="utf-8") as f:
|
|
2112
|
+
f.write(readme_text)
|
|
2113
|
+
except Exception:
|
|
2114
|
+
pass
|
|
2115
|
+
|
|
2116
|
+
t_name = self.query_one("#team_name_input", Input).value.strip() or os.path.basename(target).lstrip(".")
|
|
2117
|
+
self.notify("Publishing team manifest and syncing channel relay...", severity="information")
|
|
2118
|
+
|
|
2119
|
+
def _sync():
|
|
2120
|
+
# Publish team manifest (clones/inits, writes identity.json + README, and pushes)
|
|
2121
|
+
ok = team_mesh.publish_team_manifest(t_name, readme_text, team_dir=target)
|
|
2122
|
+
if not ok:
|
|
2123
|
+
ok = team_mesh.sync_relay_repo(target)
|
|
2124
|
+
|
|
2125
|
+
self.app.call_from_thread(self.refresh_channel_peers_ui, target)
|
|
2126
|
+
if ok:
|
|
2127
|
+
self.app.call_from_thread(self.notify, "Channel relay synced and team published!", severity="information")
|
|
2128
|
+
else:
|
|
2129
|
+
self.app.call_from_thread(self.notify, "Channel sync failed. Check relay URL and PAT permissions.", severity="error")
|
|
2130
|
+
threading.Thread(target=_sync, daemon=True).start()
|
|
2131
|
+
|
|
2132
|
+
elif btn_id == "mesh_seed_btn":
|
|
2133
|
+
import team_mesh
|
|
2134
|
+
target = self.editing_path or toolbox.get_team_dir()
|
|
2135
|
+
current_seed = team_mesh.get_or_create_user_seed(target)
|
|
2136
|
+
def handle_seed_save(new_seed):
|
|
2137
|
+
if new_seed:
|
|
2138
|
+
team_mesh.set_user_seed(new_seed, target)
|
|
2139
|
+
self.notify("Channel PSK Seed updated successfully.", severity="information")
|
|
2140
|
+
self.app.push_screen(MeshSeedModal(current_seed), handle_seed_save)
|
|
2141
|
+
return
|
|
2142
|
+
|
|
2022
2143
|
elif btn_id == "save_team_btn":
|
|
2144
|
+
readme_text = self.query_one("#team_readme_input", TextArea).text
|
|
2145
|
+
import team_mesh
|
|
2146
|
+
target = self.editing_path or toolbox.get_team_dir()
|
|
2147
|
+
team_mesh.save_relay_credentials(
|
|
2148
|
+
url=self.query_one("#mesh_relay_url_input", Input).value,
|
|
2149
|
+
user=self.query_one("#mesh_relay_user_input", Input).value,
|
|
2150
|
+
pat=self.query_one("#mesh_relay_pat_input", Input).value,
|
|
2151
|
+
team_dir=target
|
|
2152
|
+
)
|
|
2153
|
+
if self.editing_path:
|
|
2154
|
+
try:
|
|
2155
|
+
with open(os.path.join(self.editing_path, "README.md"), "w", encoding="utf-8") as f:
|
|
2156
|
+
f.write(readme_text)
|
|
2157
|
+
except Exception: pass
|
|
2158
|
+
|
|
2159
|
+
t_active_name = self.query_one("#team_name_input", Input).value.strip() or os.path.basename(self.editing_path).lstrip(".")
|
|
2160
|
+
edit_path = self.editing_path
|
|
2161
|
+
old_name_arg = old_team_name if (old_team_name and old_team_name.lower() != t_active_name.lower()) else None
|
|
2162
|
+
def _bg_publish():
|
|
2163
|
+
team_mesh.publish_team_manifest(t_active_name, readme_text, team_dir=edit_path, old_team_name=old_name_arg)
|
|
2164
|
+
self.app.call_from_thread(self.refresh_channel_peers_ui, edit_path)
|
|
2165
|
+
threading.Thread(target=_bg_publish, daemon=True).start()
|
|
2023
2166
|
t_name = self.query_one("#team_name_input", Input).value.strip()
|
|
2024
2167
|
folder_val = self.query_one("#team_folder_input", Input).value.strip()
|
|
2025
2168
|
url = self.query_one("#team_remote_url_input", Input).value.strip()
|
|
@@ -2037,12 +2180,20 @@ class TeamsModal(ModalScreen[None]):
|
|
|
2037
2180
|
|
|
2038
2181
|
settings = toolbox.load_global_settings()
|
|
2039
2182
|
registered = settings.get("registered_teams", [])
|
|
2183
|
+
old_team_name = None
|
|
2040
2184
|
for t in registered:
|
|
2041
2185
|
if os.path.abspath(os.path.expanduser(t.get("path", ""))) == target_path:
|
|
2186
|
+
old_team_name = t.get("name")
|
|
2042
2187
|
t["name"] = name
|
|
2043
2188
|
break
|
|
2044
2189
|
settings["registered_teams"] = registered
|
|
2045
2190
|
toolbox.save_global_settings(settings)
|
|
2191
|
+
|
|
2192
|
+
ts = toolbox.load_team_settings() if target_path == toolbox.get_team_dir() else {}
|
|
2193
|
+
if not old_team_name and ts.get("team_name"):
|
|
2194
|
+
old_team_name = ts.get("team_name")
|
|
2195
|
+
ts["team_name"] = name
|
|
2196
|
+
toolbox.save_team_settings(ts)
|
|
2046
2197
|
|
|
2047
2198
|
toolbox.save_team_git_credentials(url, user, pat, team_dir=target_path)
|
|
2048
2199
|
self.refresh_list()
|
|
@@ -2052,6 +2203,13 @@ class TeamsModal(ModalScreen[None]):
|
|
|
2052
2203
|
target_path = folder_val if os.path.isabs(folder_val) else os.path.join(str(Path.home()), folder_val)
|
|
2053
2204
|
name = t_name or os.path.basename(target_path).lstrip(".")
|
|
2054
2205
|
|
|
2206
|
+
if readme_text:
|
|
2207
|
+
os.makedirs(target_path, exist_ok=True)
|
|
2208
|
+
try:
|
|
2209
|
+
with open(os.path.join(target_path, "README.md"), "w", encoding="utf-8") as f:
|
|
2210
|
+
f.write(readme_text)
|
|
2211
|
+
except Exception: pass
|
|
2212
|
+
|
|
2055
2213
|
self.dismiss()
|
|
2056
2214
|
self.agent_view.switch_team(target_path, display_name=name)
|
|
2057
2215
|
toolbox.save_team_git_credentials(url, user, pat, team_dir=target_path)
|
|
@@ -2100,6 +2258,9 @@ class TeamsModal(ModalScreen[None]):
|
|
|
2100
2258
|
import keyring
|
|
2101
2259
|
keyring.delete_password("Federate", f"git_user_{team_tag}")
|
|
2102
2260
|
keyring.delete_password("Federate", f"git_pat_{team_tag}")
|
|
2261
|
+
keyring.delete_password("Federate", f"mesh_relay_user_{team_tag}")
|
|
2262
|
+
keyring.delete_password("Federate", f"mesh_relay_pat_{team_tag}")
|
|
2263
|
+
keyring.delete_password("Federate", f"mesh_seed_{team_tag}")
|
|
2103
2264
|
try:
|
|
2104
2265
|
import mcp_handler
|
|
2105
2266
|
mcp_handler._clear_mcp_keyring_chunks(keyring, team_dir=t_path)
|
|
@@ -2117,8 +2278,19 @@ class TeamsModal(ModalScreen[None]):
|
|
|
2117
2278
|
elif self.editing_path == t_path:
|
|
2118
2279
|
self.clear_form()
|
|
2119
2280
|
|
|
2281
|
+
import team_mesh
|
|
2282
|
+
# Unpublish team manifest and remove from relay repo
|
|
2283
|
+
try:
|
|
2284
|
+
team_mesh.unpublish_team(t_name, team_dir=t_path)
|
|
2285
|
+
except Exception:
|
|
2286
|
+
pass
|
|
2287
|
+
|
|
2120
2288
|
if choice == "purge":
|
|
2121
2289
|
import shutil
|
|
2290
|
+
relay_local = team_mesh.get_relay_local_dir(t_path)
|
|
2291
|
+
if os.path.exists(relay_local):
|
|
2292
|
+
try: shutil.rmtree(relay_local, ignore_errors=True)
|
|
2293
|
+
except Exception: pass
|
|
2122
2294
|
if t_path != str(Path.home()) and os.path.exists(t_path) and len(t_path) > 3:
|
|
2123
2295
|
try:
|
|
2124
2296
|
shutil.rmtree(t_path, ignore_errors=True)
|
|
@@ -2572,6 +2744,76 @@ class ScheduleModal(ModalScreen[None]):
|
|
|
2572
2744
|
self.refresh_list()
|
|
2573
2745
|
self.notify("Loaded task into inputs for modification.", severity="information")
|
|
2574
2746
|
|
|
2747
|
+
class IncomingDispatchModal(ModalScreen[str]):
|
|
2748
|
+
DEFAULT_CSS = """
|
|
2749
|
+
IncomingDispatchModal { align: center middle; background: $background 60%; }
|
|
2750
|
+
#dispatch_dialog { width: 75; height: auto; max-height: 80%; border: thick $accent; background: $surface; padding: 1 2; }
|
|
2751
|
+
.dispatch_header { background: $accent; color: $text; text-style: bold; text-align: center; width: 100%; height: 1; margin-bottom: 1; }
|
|
2752
|
+
.dispatch_body {
|
|
2753
|
+
margin: 1 0;
|
|
2754
|
+
max-height: 14;
|
|
2755
|
+
overflow-y: scroll;
|
|
2756
|
+
border: round $primary;
|
|
2757
|
+
background: $boost;
|
|
2758
|
+
padding: 1;
|
|
2759
|
+
}
|
|
2760
|
+
.dispatch_body Label {
|
|
2761
|
+
text-wrap: wrap;
|
|
2762
|
+
width: 100%;
|
|
2763
|
+
height: auto;
|
|
2764
|
+
}
|
|
2765
|
+
.dispatch_msg { margin: 1 0; text-style: bold; }
|
|
2766
|
+
.buttons { height: auto; align: right middle; margin-top: 1; }
|
|
2767
|
+
.buttons Button { margin-left: 1; }
|
|
2768
|
+
"""
|
|
2769
|
+
|
|
2770
|
+
def __init__(self, sender_team: str, instruction: str, attachments: list, **kwargs):
|
|
2771
|
+
super().__init__(**kwargs)
|
|
2772
|
+
self.sender_team = sender_team
|
|
2773
|
+
self.instruction = instruction
|
|
2774
|
+
self.attachments = attachments
|
|
2775
|
+
self.time_left = 300
|
|
2776
|
+
self.timer = None
|
|
2777
|
+
|
|
2778
|
+
def compose(self) -> ComposeResult:
|
|
2779
|
+
with Vertical(id="dispatch_dialog"):
|
|
2780
|
+
yield Label(f" Incoming Dispatch from Team: {self.sender_team}", classes="dispatch_header")
|
|
2781
|
+
with Vertical(classes="dispatch_body"):
|
|
2782
|
+
yield Label(f"[bold cyan]Instruction:[/bold cyan]\n{self.instruction}\n")
|
|
2783
|
+
if self.attachments:
|
|
2784
|
+
files_str = "\n".join(f" • {os.path.basename(f)}" for f in self.attachments)
|
|
2785
|
+
yield Label(f"[bold yellow]Attachments ({len(self.attachments)}):[/bold yellow]\n{files_str}")
|
|
2786
|
+
else:
|
|
2787
|
+
yield Label("[dim]No attachments accompanied this dispatch.[/dim]")
|
|
2788
|
+
yield Label(f"Auto-accepting in [bold yellow]{self.time_left}s[/bold yellow] if no action taken...", id="dispatch_countdown", classes="dispatch_msg")
|
|
2789
|
+
with Horizontal(classes="buttons"):
|
|
2790
|
+
yield Button("Accept & Run", id="accept_btn", variant="success")
|
|
2791
|
+
yield Button("Dismiss", id="dismiss_btn", variant="error")
|
|
2792
|
+
|
|
2793
|
+
def on_mount(self):
|
|
2794
|
+
self.query_one("#accept_btn").focus()
|
|
2795
|
+
self.timer = self.set_interval(1.0, self.update_countdown)
|
|
2796
|
+
|
|
2797
|
+
def update_countdown(self):
|
|
2798
|
+
self.time_left -= 1
|
|
2799
|
+
if self.time_left <= 0:
|
|
2800
|
+
if self.timer:
|
|
2801
|
+
self.timer.stop()
|
|
2802
|
+
self.dismiss("accept")
|
|
2803
|
+
else:
|
|
2804
|
+
try:
|
|
2805
|
+
self.query_one("#dispatch_countdown", Label).update(
|
|
2806
|
+
f"Auto-accepting in [bold yellow]{self.time_left}s[/bold yellow] if no action taken..."
|
|
2807
|
+
)
|
|
2808
|
+
except Exception:
|
|
2809
|
+
pass
|
|
2810
|
+
|
|
2811
|
+
@on(Button.Pressed)
|
|
2812
|
+
def handle_choice(self, event: Button.Pressed):
|
|
2813
|
+
if self.timer:
|
|
2814
|
+
self.timer.stop()
|
|
2815
|
+
self.dismiss("accept" if event.button.id == "accept_btn" else "dismiss")
|
|
2816
|
+
|
|
2575
2817
|
class ScheduledTaskPromptModal(ModalScreen[str]):
|
|
2576
2818
|
DEFAULT_CSS = """
|
|
2577
2819
|
ScheduledTaskPromptModal { align: center middle; background: $background 60%; }
|
|
@@ -3981,6 +4223,14 @@ class AIAgentView(Vertical):
|
|
|
3981
4223
|
# Reload MCP background sessions for the new team
|
|
3982
4224
|
toolbox.reload_mcp_servers()
|
|
3983
4225
|
|
|
4226
|
+
# Auto-publish identity manifest to relay for the newly activated team
|
|
4227
|
+
def _bg_mesh_init():
|
|
4228
|
+
try:
|
|
4229
|
+
import team_mesh
|
|
4230
|
+
team_mesh.auto_publish_manifest(clean_dir)
|
|
4231
|
+
except Exception: pass
|
|
4232
|
+
threading.Thread(target=_bg_mesh_init, daemon=True).start()
|
|
4233
|
+
|
|
3984
4234
|
self._write_log(Rule(title=f"[bold #f2a813]TEAM WORKSPACE: {d_name.upper()}", style="dim"))
|
|
3985
4235
|
self._write_log(get_welcome_banner(self))
|
|
3986
4236
|
self.update_tokens()
|
|
@@ -4985,7 +5235,103 @@ class AIAgentView(Vertical):
|
|
|
4985
5235
|
candidate = nxt
|
|
4986
5236
|
return candidate
|
|
4987
5237
|
|
|
5238
|
+
@work(thread=True)
|
|
5239
|
+
def check_mesh_inbox(self):
|
|
5240
|
+
"""Wire 3: Polls team channel relay, processes ACKs, and stages incoming dispatches."""
|
|
5241
|
+
if getattr(self, "_inbox_worker_busy", False) or getattr(self, "_dispatch_prompt_active", False) or getattr(self, "_running_agents", None):
|
|
5242
|
+
return
|
|
5243
|
+
|
|
5244
|
+
self._inbox_worker_busy = True
|
|
5245
|
+
try:
|
|
5246
|
+
self._do_check_mesh_inbox()
|
|
5247
|
+
finally:
|
|
5248
|
+
self._inbox_worker_busy = False
|
|
5249
|
+
|
|
5250
|
+
def _do_check_mesh_inbox(self):
|
|
5251
|
+
|
|
5252
|
+
try:
|
|
5253
|
+
import team_mesh
|
|
5254
|
+
except ImportError:
|
|
5255
|
+
return
|
|
5256
|
+
|
|
5257
|
+
team_dir = toolbox.get_team_dir()
|
|
5258
|
+
team_mesh.sync_relay_repo(team_dir)
|
|
5259
|
+
team_mesh.process_acks_and_purge(team_dir)
|
|
5260
|
+
|
|
5261
|
+
my_team = toolbox.get_team_name(team_dir)
|
|
5262
|
+
relay_dir = team_mesh.get_relay_local_dir(team_dir)
|
|
5263
|
+
my_inbox = os.path.join(relay_dir, "messages", my_team)
|
|
5264
|
+
if not os.path.exists(my_inbox):
|
|
5265
|
+
return
|
|
5266
|
+
|
|
5267
|
+
fedmsg_files = [f for f in os.listdir(my_inbox) if f.endswith(".fedmsg")]
|
|
5268
|
+
if not fedmsg_files:
|
|
5269
|
+
return
|
|
5270
|
+
|
|
5271
|
+
remaining_count = len(fedmsg_files) - 1
|
|
5272
|
+
fname = fedmsg_files[0]
|
|
5273
|
+
fpath = os.path.join(my_inbox, fname)
|
|
5274
|
+
processed_path = fpath + ".processed"
|
|
5275
|
+
try:
|
|
5276
|
+
# Rename immediately to prevent duplicate prompts on the next cycle
|
|
5277
|
+
os.replace(fpath, processed_path)
|
|
5278
|
+
with open(processed_path, "rb") as f:
|
|
5279
|
+
raw = f.read()
|
|
5280
|
+
|
|
5281
|
+
header = json.loads(raw.split(b"\n---SIG---\n")[0].decode("utf-8"))
|
|
5282
|
+
msg_id = header["msg_id"]
|
|
5283
|
+
sender_team = header["from_team"]
|
|
5284
|
+
|
|
5285
|
+
stage_dir = os.path.join(team_dir, ".inbox_artifacts")
|
|
5286
|
+
manifest, extracted = team_mesh.unpack_and_decrypt(raw, stage_dir, team_dir=team_dir)
|
|
5287
|
+
|
|
5288
|
+
# Single combined triple-tick ACK to avoid redundant network pushes
|
|
5289
|
+
team_mesh.emit_ack(msg_id, sender_team, status="triple_tick", team_dir=team_dir)
|
|
5290
|
+
|
|
5291
|
+
task_prompt = (
|
|
5292
|
+
f"[Dispatch from Team {sender_team}]: {manifest['instruction']}\n\n"
|
|
5293
|
+
f"Note: To send a response back to Team {sender_team}, use the tool "
|
|
5294
|
+
f"`send_team_dispatch(target_team='{sender_team}', instruction='...')`.\n"
|
|
5295
|
+
f"Note: You will be responding on behalf of your team not personally, so formulate the response accordingly."
|
|
5296
|
+
)
|
|
5297
|
+
if extracted:
|
|
5298
|
+
escaped_files = [f.replace(" ", r"\ ") for f in extracted]
|
|
5299
|
+
task_prompt += "\n\nAttached Files (Pre-staged locally):\n" + "\n".join(f"&{ef}" for ef in escaped_files)
|
|
5300
|
+
|
|
5301
|
+
if remaining_count > 0:
|
|
5302
|
+
self.notify(f"Note: {remaining_count} additional dispatch(es) queued in inbox.", severity="information")
|
|
5303
|
+
|
|
5304
|
+
self._dispatch_prompt_active = True
|
|
5305
|
+
def prompt_user():
|
|
5306
|
+
try:
|
|
5307
|
+
def handle_choice(choice: str):
|
|
5308
|
+
self._dispatch_prompt_active = False
|
|
5309
|
+
if choice == "accept":
|
|
5310
|
+
chat_input = self.query_one("#ai_chat_input", ChatInput)
|
|
5311
|
+
agent_name = getattr(self.active_agent, "name", "Rita")
|
|
5312
|
+
self.on_input_submitted(ChatInput.Submitted(chat_input, f"{task_prompt}"))
|
|
5313
|
+
else:
|
|
5314
|
+
staged_path = os.path.join(".inbox_artifacts", manifest.get("msg_id", ""))
|
|
5315
|
+
self.log_to_ui(
|
|
5316
|
+
f"[dim yellow]Incoming dispatch from Team '{sender_team}' was dismissed.\n"
|
|
5317
|
+
f"• Instruction: {manifest.get('instruction', '')[:120]}\n"
|
|
5318
|
+
f"• Staged files preserved at: {staged_path}[/dim yellow]"
|
|
5319
|
+
)
|
|
5320
|
+
self.app.push_screen(
|
|
5321
|
+
IncomingDispatchModal(sender_team, manifest.get("instruction", ""), extracted),
|
|
5322
|
+
handle_choice
|
|
5323
|
+
)
|
|
5324
|
+
except Exception as pe:
|
|
5325
|
+
self._dispatch_prompt_active = False
|
|
5326
|
+
self.log_to_ui(f"[bold red]Failed to present dispatch modal: {pe}[/bold red]")
|
|
5327
|
+
|
|
5328
|
+
self.app.call_from_thread(prompt_user)
|
|
5329
|
+
return
|
|
5330
|
+
except Exception as e:
|
|
5331
|
+
self.log_to_ui(f"[dim red]Mesh relay verification failed: {e}[/dim red]")
|
|
5332
|
+
|
|
4988
5333
|
def tick_scheduler(self):
|
|
5334
|
+
self.check_mesh_inbox()
|
|
4989
5335
|
if getattr(self, "shell_mode", False) or not hasattr(self, "schedule_manager") or getattr(self, "_scheduler_prompt_active", False):
|
|
4990
5336
|
return
|
|
4991
5337
|
|
|
@@ -5145,6 +5491,12 @@ class AIAgentView(Vertical):
|
|
|
5145
5491
|
if not remote_url or not pat:
|
|
5146
5492
|
return
|
|
5147
5493
|
|
|
5494
|
+
# 1. Auto-publish mesh manifest to channel relay if configured
|
|
5495
|
+
try:
|
|
5496
|
+
import team_mesh
|
|
5497
|
+
team_mesh.auto_publish_manifest(t_dir)
|
|
5498
|
+
except Exception: pass
|
|
5499
|
+
|
|
5148
5500
|
ok, msg = toolbox.sync_team_remote(action="pull", team_dir=t_dir)
|
|
5149
5501
|
if ok:
|
|
5150
5502
|
def _apply_updates():
|
|
@@ -427,7 +427,7 @@ def get_executor_core(agent_view, agent_config: AgentConfig):
|
|
|
427
427
|
return True
|
|
428
428
|
return False
|
|
429
429
|
|
|
430
|
-
raw_tools = [toolbox.search_web, toolbox.perform_research, toolbox.render_pdf, toolbox.update_core_memory, toolbox.save_skill, toolbox.read_skill, toolbox.distill_journey, toolbox.delete_passive_skill, toolbox.list_skills, toolbox.mark_quagmire, toolbox.get_user_clarification, toolbox.search_episodic_memory, toolbox.retrieve_episodic_memory, toolbox.prepare_active_skill, toolbox.finalize_active_skill, toolbox.manage_active_skill, toolbox.fix_active_skill, toolbox.get_toolresult]
|
|
430
|
+
raw_tools = [toolbox.search_web, toolbox.perform_research, toolbox.render_pdf, toolbox.update_core_memory, toolbox.save_skill, toolbox.read_skill, toolbox.distill_journey, toolbox.delete_passive_skill, toolbox.list_skills, toolbox.mark_quagmire, toolbox.get_user_clarification, toolbox.search_episodic_memory, toolbox.retrieve_episodic_memory, toolbox.prepare_active_skill, toolbox.finalize_active_skill, toolbox.manage_active_skill, toolbox.fix_active_skill, toolbox.get_toolresult, toolbox.send_team_dispatch]
|
|
431
431
|
if is_nomem:
|
|
432
432
|
raw_tools = [t for t in raw_tools if getattr(t, "name", "") not in NOMEM_EXCLUDED_TOOLS]
|
|
433
433
|
raw_tools.extend(toolbox.load_dynamic_tools(agent_config.name))
|