swarmly 0.9.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 (81) hide show
  1. swarmly/__init__.py +42 -0
  2. swarmly/_aliases.py +30 -0
  3. swarmly/adapters/__init__.py +17 -0
  4. swarmly/adapters/base.py +54 -0
  5. swarmly/adapters/deepseek.py +58 -0
  6. swarmly/adapters/gemini.py +60 -0
  7. swarmly/adapters/hermes.py +46 -0
  8. swarmly/adapters/openai_swarm.py +68 -0
  9. swarmly/bus.py +331 -0
  10. swarmly/client.py +216 -0
  11. swarmly/crypto.py +221 -0
  12. swarmly/github/__init__.py +5 -0
  13. swarmly/github/client.py +305 -0
  14. swarmly/github/watch.py +293 -0
  15. swarmly/keygen.py +247 -0
  16. swarmly/logsetup.py +121 -0
  17. swarmly/models.py +394 -0
  18. swarmly/server.py +301 -0
  19. swarmly/swarm/__init__.py +23 -0
  20. swarmly/swarm/cli.py +483 -0
  21. swarmly/swarm/doc.py +124 -0
  22. swarmly/swarm/doorbell.py +237 -0
  23. swarmly/swarm/envelope.py +195 -0
  24. swarmly/swarm/governor.py +344 -0
  25. swarmly/swarm/inbox.py +287 -0
  26. swarmly/swarm/keys.py +95 -0
  27. swarmly/swarm/lanes.py +376 -0
  28. swarmly/swarm/mcp.py +181 -0
  29. swarmly/swarm/mcp_setup.py +617 -0
  30. swarmly/swarm/projection.py +719 -0
  31. swarmly/swarm/protocol.py +288 -0
  32. swarmly/swarm/protocol.yaml +268 -0
  33. swarmly/telegram/__init__.py +82 -0
  34. swarmly/telegram/acks.py +140 -0
  35. swarmly/telegram/adapters/__init__.py +146 -0
  36. swarmly/telegram/adapters/antigravity.py +1304 -0
  37. swarmly/telegram/adapters/base.py +796 -0
  38. swarmly/telegram/adapters/claude.py +337 -0
  39. swarmly/telegram/adapters/codex.py +616 -0
  40. swarmly/telegram/adapters/handover.py +141 -0
  41. swarmly/telegram/adapters/hermes.py +74 -0
  42. swarmly/telegram/adapters/reasonix.py +297 -0
  43. swarmly/telegram/channel.py +3961 -0
  44. swarmly/telegram/cli.py +995 -0
  45. swarmly/telegram/commands.py +120 -0
  46. swarmly/telegram/config.py +1310 -0
  47. swarmly/telegram/endpoint.py +800 -0
  48. swarmly/telegram/git_sync.py +109 -0
  49. swarmly/telegram/guard.py +244 -0
  50. swarmly/telegram/init.py +403 -0
  51. swarmly/telegram/oslock.py +92 -0
  52. swarmly/telegram/poll.py +2134 -0
  53. swarmly/telegram/projects.py +141 -0
  54. swarmly/telegram/relay.py +131 -0
  55. swarmly/telegram/replies.py +330 -0
  56. swarmly/telegram/roles/__init__.py +140 -0
  57. swarmly/telegram/roles/coordinator.md +29 -0
  58. swarmly/telegram/roles/developer.md +21 -0
  59. swarmly/telegram/roles/qa-tester.md +20 -0
  60. swarmly/telegram/roles/researcher.md +17 -0
  61. swarmly/telegram/roles/reviewer.md +21 -0
  62. swarmly/telegram/roster.py +270 -0
  63. swarmly/telegram/selftest.py +405 -0
  64. swarmly/telegram/templates/a2a_config.json +8 -0
  65. swarmly/telegram/templates/config.example.yaml +66 -0
  66. swarmly/telegram/topic_memory.py +228 -0
  67. swarmly/telegram/topic_open.py +131 -0
  68. swarmly/telegram/topics.py +141 -0
  69. swarmly/telegram/wire.py +302 -0
  70. swarmly/transports/__init__.py +58 -0
  71. swarmly/transports/base.py +149 -0
  72. swarmly/transports/folder.py +62 -0
  73. swarmly/transports/gdrive.py +206 -0
  74. swarmly/transports/git.py +344 -0
  75. swarmly-0.9.0.dist-info/METADATA +402 -0
  76. swarmly-0.9.0.dist-info/RECORD +81 -0
  77. swarmly-0.9.0.dist-info/WHEEL +5 -0
  78. swarmly-0.9.0.dist-info/entry_points.txt +7 -0
  79. swarmly-0.9.0.dist-info/licenses/LICENSE +21 -0
  80. swarmly-0.9.0.dist-info/licenses/THIRD_PARTY_NOTICES.md +70 -0
  81. swarmly-0.9.0.dist-info/top_level.txt +1 -0
swarmly/__init__.py ADDED
@@ -0,0 +1,42 @@
1
+ """
2
+ Swarmly: coordinate coding-agent CLIs from different vendors, on different machines.
3
+
4
+ The import package was ``a2a`` before the rename; the wire identifiers (``a2a/v1``,
5
+ ``a2a/2``) and the ``A2A_*`` environment variables keep their names.
6
+ """
7
+
8
+ __version__ = "0.9.0"
9
+ __protocol__ = "a2a/v1.0"
10
+
11
+ from swarmly.models import (
12
+ A2AMessage,
13
+ SenderInfo,
14
+ RecipientInfo,
15
+ MessageIntent,
16
+ MessagePriority,
17
+ TaskClaimPayload,
18
+ TaskHandoffPayload,
19
+ PRReviewRequestPayload,
20
+ PRReviewVerdictPayload,
21
+ FalsificationPayload,
22
+ )
23
+ from swarmly.crypto import CryptoAuth, KeyPair
24
+ from swarmly.bus import DurableBus
25
+ from swarmly.client import A2AClient
26
+
27
+ __all__ = [
28
+ "A2AMessage",
29
+ "SenderInfo",
30
+ "RecipientInfo",
31
+ "MessageIntent",
32
+ "MessagePriority",
33
+ "TaskClaimPayload",
34
+ "TaskHandoffPayload",
35
+ "PRReviewRequestPayload",
36
+ "PRReviewVerdictPayload",
37
+ "FalsificationPayload",
38
+ "CryptoAuth",
39
+ "KeyPair",
40
+ "DurableBus",
41
+ "A2AClient",
42
+ ]
swarmly/_aliases.py ADDED
@@ -0,0 +1,30 @@
1
+ """The command names from before the rename to Swarmly, kept for one release.
2
+
3
+ Each prints one line to stderr naming its replacement, then runs it unchanged, so a
4
+ launcher or scheduled task still using an old name keeps working and its log says so.
5
+ """
6
+
7
+ import sys
8
+
9
+
10
+ def _note(old: str, new: str) -> None:
11
+ print(f"{old}: renamed to {new}; this alias goes away in the next release",
12
+ file=sys.stderr)
13
+
14
+
15
+ def a2a_telegram() -> None:
16
+ _note("a2a-telegram", "swarmly-telegram")
17
+ from swarmly.telegram.cli import main
18
+ sys.exit(main())
19
+
20
+
21
+ def a2a() -> None:
22
+ _note("a2a", "swarmly")
23
+ from swarmly.swarm.cli import main
24
+ sys.exit(main())
25
+
26
+
27
+ def a2a_keygen() -> None:
28
+ _note("a2a-keygen", "swarmly-keygen")
29
+ from swarmly.keygen import main
30
+ sys.exit(main())
@@ -0,0 +1,17 @@
1
+ """
2
+ Multi-Agent Framework Adapters for Swarmly.
3
+ """
4
+
5
+ from swarmly.adapters.base import BaseAgentAdapter
6
+ from swarmly.adapters.openai_swarm import OpenAISwarmAdapter
7
+ from swarmly.adapters.deepseek import DeepSeekAdapter
8
+ from swarmly.adapters.gemini import GeminiAdapter
9
+ from swarmly.adapters.hermes import HermesAdapter
10
+
11
+ __all__ = [
12
+ "BaseAgentAdapter",
13
+ "OpenAISwarmAdapter",
14
+ "DeepSeekAdapter",
15
+ "GeminiAdapter",
16
+ "HermesAdapter",
17
+ ]
@@ -0,0 +1,54 @@
1
+ """
2
+ Base abstract adapter defining interface for heterogeneous agent frameworks.
3
+ """
4
+
5
+ from __future__ import annotations
6
+ from abc import ABC, abstractmethod
7
+ from typing import Any, Dict, List, Optional
8
+ from swarmly.models import A2AMessage, MessageIntent, MessagePriority
9
+ from swarmly.client import A2AClient
10
+
11
+
12
+ class BaseAgentAdapter(ABC):
13
+ """Abstract adapter connecting a specific agent framework to Swarmly."""
14
+
15
+ def __init__(self, client: A2AClient):
16
+ self.client = client
17
+ self.agent_id = client.agent_id
18
+
19
+ @abstractmethod
20
+ def export_tools(self) -> List[Dict[str, Any]]:
21
+ """Export tool definitions suitable for the framework's tool-calling API."""
22
+ pass
23
+
24
+ async def execute_tool_call(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
25
+ """Dispatch a tool call triggered by the underlying LLM."""
26
+ if tool_name == "a2a_send_message":
27
+ msg = await self.client.send_message(
28
+ intent=arguments.get("intent", MessageIntent.QUERY_REQUEST),
29
+ payload=arguments.get("payload", {}),
30
+ recipient_id=arguments.get("recipient_id", "*"),
31
+ priority=arguments.get("priority", MessagePriority.ROUTINE),
32
+ correlation_id=arguments.get("correlation_id"),
33
+ )
34
+ return {"status": "sent", "message_id": msg.message_id}
35
+
36
+ elif tool_name == "a2a_read_inbox":
37
+ messages = self.client.bus.read_inbox(verify_signatures=True)
38
+ return {
39
+ "count": len(messages),
40
+ "messages": [
41
+ {
42
+ "message_id": m.message_id,
43
+ "sender": m.sender.agent_id,
44
+ "intent": m.intent.value,
45
+ "priority": m.priority.value,
46
+ "payload": m.payload,
47
+ "is_valid": valid,
48
+ "status": status,
49
+ }
50
+ for m, valid, status in messages
51
+ ]
52
+ }
53
+
54
+ return {"error": f"Unknown tool: {tool_name}"}
@@ -0,0 +1,58 @@
1
+ """
2
+ DeepSeek Adapter for Swarmly.
3
+ Supports both programmatic integration and CLI Aider/runner workflows.
4
+ """
5
+
6
+ from __future__ import annotations
7
+ from typing import Any, Dict, List
8
+ from swarmly.adapters.base import BaseAgentAdapter
9
+ from swarmly.models import MessageIntent, MessagePriority
10
+
11
+
12
+ class DeepSeekAdapter(BaseAgentAdapter):
13
+ """Adapter for DeepSeek-R1 and DeepSeek-V3 reasoning agents."""
14
+
15
+ def export_tools(self) -> List[Dict[str, Any]]:
16
+ return [
17
+ {
18
+ "name": "a2a_send_falsification_report",
19
+ "description": "Publish a formal falsification or statistical audit to the swarm with citations.",
20
+ "parameters": {
21
+ "type": "object",
22
+ "required": ["hypothesis", "predicted_metric", "measured_metric", "verdict"],
23
+ "properties": {
24
+ "hypothesis": {"type": "string"},
25
+ "predicted_metric": {"type": "string"},
26
+ "measured_metric": {"type": "string"},
27
+ "bounds_violated": {"type": "boolean"},
28
+ "verdict": {"type": "string"},
29
+ "citation_scripts": {"type": "array", "items": {"type": "string"}}
30
+ }
31
+ }
32
+ }
33
+ ]
34
+
35
+ async def publish_falsification(
36
+ self,
37
+ hypothesis: str,
38
+ predicted_metric: str,
39
+ measured_metric: str,
40
+ bounds_violated: bool,
41
+ verdict: str,
42
+ citation_scripts: List[str]
43
+ ):
44
+ """Helper to post a typed falsification report to all agents."""
45
+ payload = {
46
+ "hypothesis": hypothesis,
47
+ "predicted_metric": predicted_metric,
48
+ "measured_metric": measured_metric,
49
+ "bounds_violated": bounds_violated,
50
+ "verdict": verdict,
51
+ "citation_scripts": citation_scripts
52
+ }
53
+ return await self.client.send_message(
54
+ intent=MessageIntent.FALSIFICATION_REPORT,
55
+ payload=payload,
56
+ recipient_id="*",
57
+ priority=MessagePriority.HIGH
58
+ )
@@ -0,0 +1,60 @@
1
+ """
2
+ Google Gemini and Antigravity Adapter for Swarmly.
3
+ """
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Dict, List
7
+ from swarmly.adapters.base import BaseAgentAdapter
8
+ from swarmly.models import MessageIntent, MessagePriority
9
+
10
+
11
+ class GeminiAdapter(BaseAgentAdapter):
12
+ """Adapter for Google Gemini and Antigravity agents."""
13
+
14
+ def export_tools(self) -> List[Dict[str, Any]]:
15
+ return [
16
+ {
17
+ "name": "a2a_handoff_task",
18
+ "description": "Formally hand off an experimental task to a peer agent with pre-registered bounds.",
19
+ "parameters": {
20
+ "type": "object",
21
+ "required": ["task_id", "git_commit_sha", "description", "pre_registered_hypothesis", "expected_bounds"],
22
+ "properties": {
23
+ "task_id": {"type": "string"},
24
+ "git_commit_sha": {"type": "string"},
25
+ "description": {"type": "string"},
26
+ "pre_registered_hypothesis": {"type": "string"},
27
+ "expected_bounds": {"type": "array", "items": {"type": "number"}},
28
+ "verification_command": {"type": "string"},
29
+ "target_output": {"type": "string"}
30
+ }
31
+ }
32
+ }
33
+ ]
34
+
35
+ async def handoff_task(
36
+ self,
37
+ task_id: str,
38
+ git_commit_sha: str,
39
+ description: str,
40
+ hypothesis: str,
41
+ bounds: List[float],
42
+ cmd: str = "",
43
+ target: str = "",
44
+ recipient_id: str = "hermes"
45
+ ):
46
+ payload = {
47
+ "task_id": task_id,
48
+ "git_commit_sha": git_commit_sha,
49
+ "description": description,
50
+ "pre_registered_hypothesis": hypothesis,
51
+ "expected_bounds": bounds,
52
+ "verification_command": cmd,
53
+ "target_output": target
54
+ }
55
+ return await self.client.send_message(
56
+ intent=MessageIntent.TASK_HANDOFF,
57
+ payload=payload,
58
+ recipient_id=recipient_id,
59
+ priority=MessagePriority.HIGH
60
+ )
@@ -0,0 +1,46 @@
1
+ """
2
+ Hermes and Local vLLM Agent Adapter for Swarmly.
3
+ """
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Dict, List
7
+ from swarmly.adapters.base import BaseAgentAdapter
8
+ from swarmly.models import MessageIntent, MessagePriority
9
+
10
+
11
+ class HermesAdapter(BaseAgentAdapter):
12
+ """Adapter for Hermes agents running on Linux/vLLM compute nodes."""
13
+
14
+ def export_tools(self) -> List[Dict[str, Any]]:
15
+ return [
16
+ {
17
+ "name": "a2a_claim_task",
18
+ "description": "Claim a research or feature engineering task atomically.",
19
+ "parameters": {
20
+ "type": "object",
21
+ "required": ["task_id", "topic"],
22
+ "properties": {
23
+ "task_id": {"type": "string"},
24
+ "topic": {"type": "string"},
25
+ "branch": {"type": "string"},
26
+ "claimed_files": {"type": "array", "items": {"type": "string"}},
27
+ "rationale": {"type": "string"}
28
+ }
29
+ }
30
+ }
31
+ ]
32
+
33
+ async def claim_task(self, task_id: str, topic: str, branch: str, files: List[str], rationale: str):
34
+ payload = {
35
+ "task_id": task_id,
36
+ "topic": topic,
37
+ "branch": branch,
38
+ "claimed_files": files,
39
+ "rationale": rationale
40
+ }
41
+ return await self.client.send_message(
42
+ intent=MessageIntent.TASK_CLAIM,
43
+ payload=payload,
44
+ recipient_id="*",
45
+ priority=MessagePriority.HIGH
46
+ )
@@ -0,0 +1,68 @@
1
+ """
2
+ OpenAI Swarm and Function Calling Adapter for Swarmly.
3
+ Exports tools conforming to standard OpenAI Chat Completion JSON schemas.
4
+ """
5
+
6
+ from __future__ import annotations
7
+ from typing import Any, Dict, List
8
+ from swarmly.adapters.base import BaseAgentAdapter
9
+
10
+
11
+ class OpenAISwarmAdapter(BaseAgentAdapter):
12
+ """Adapter for ChatGPT, OpenAI Swarm, AutoGen, and CrewAI."""
13
+
14
+ def export_tools(self) -> List[Dict[str, Any]]:
15
+ """Export tool specifications in standard OpenAI function format."""
16
+ return [
17
+ {
18
+ "type": "function",
19
+ "function": {
20
+ "name": "a2a_send_message",
21
+ "description": "Send a verified A2A message to the swarm (Hermes, DeepSeek, Antigravity, MiniMax) via WebSocket or Git.",
22
+ "parameters": {
23
+ "type": "object",
24
+ "required": ["intent", "payload"],
25
+ "properties": {
26
+ "intent": {
27
+ "type": "string",
28
+ "enum": [
29
+ "TASK_PROPOSE", "TASK_CLAIM", "TASK_APPROVE", "TASK_HANDOFF",
30
+ "PR_REVIEW_REQUEST", "PR_REVIEW_VERDICT", "FALSIFICATION_REPORT",
31
+ "EXPERIMENT_REGISTER", "QUERY_REQUEST", "QUERY_RESPONSE", "ESCALATE_BLOCKER"
32
+ ],
33
+ "description": "The operational intent of this message"
34
+ },
35
+ "recipient_id": {
36
+ "type": "string",
37
+ "description": "Target agent ID (e.g. 'antigravity', 'hermes', 'deepseek') or '*' for broadcast",
38
+ "default": "*"
39
+ },
40
+ "priority": {
41
+ "type": "string",
42
+ "enum": ["ROUTINE", "HIGH", "BLOCKING"],
43
+ "default": "ROUTINE"
44
+ },
45
+ "correlation_id": {
46
+ "type": "string",
47
+ "description": "Optional correlation ID linking to a task or PR"
48
+ },
49
+ "payload": {
50
+ "type": "object",
51
+ "description": "Structured message payload"
52
+ }
53
+ }
54
+ }
55
+ }
56
+ },
57
+ {
58
+ "type": "function",
59
+ "function": {
60
+ "name": "a2a_read_inbox",
61
+ "description": "Read and cryptographically verify all pending incoming messages from the swarm inbox.",
62
+ "parameters": {
63
+ "type": "object",
64
+ "properties": {}
65
+ }
66
+ }
67
+ }
68
+ ]