gobby 0.2.6__py3-none-any.whl → 0.2.8__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.
- gobby/__init__.py +1 -1
- gobby/adapters/__init__.py +2 -1
- gobby/adapters/claude_code.py +96 -35
- gobby/adapters/codex_impl/__init__.py +28 -0
- gobby/adapters/codex_impl/adapter.py +722 -0
- gobby/adapters/codex_impl/client.py +679 -0
- gobby/adapters/codex_impl/protocol.py +20 -0
- gobby/adapters/codex_impl/types.py +68 -0
- gobby/adapters/gemini.py +140 -38
- gobby/agents/definitions.py +11 -1
- gobby/agents/isolation.py +525 -0
- gobby/agents/registry.py +11 -0
- gobby/agents/sandbox.py +261 -0
- gobby/agents/session.py +1 -0
- gobby/agents/spawn.py +42 -287
- gobby/agents/spawn_executor.py +415 -0
- gobby/agents/spawners/__init__.py +24 -0
- gobby/agents/spawners/command_builder.py +189 -0
- gobby/agents/spawners/embedded.py +21 -2
- gobby/agents/spawners/headless.py +21 -2
- gobby/agents/spawners/macos.py +26 -1
- gobby/agents/spawners/prompt_manager.py +125 -0
- gobby/cli/__init__.py +0 -2
- gobby/cli/install.py +4 -4
- gobby/cli/installers/claude.py +6 -0
- gobby/cli/installers/gemini.py +6 -0
- gobby/cli/installers/shared.py +103 -4
- gobby/cli/memory.py +185 -0
- gobby/cli/sessions.py +1 -1
- gobby/cli/utils.py +9 -2
- gobby/clones/git.py +177 -0
- gobby/config/__init__.py +12 -97
- gobby/config/app.py +10 -94
- gobby/config/extensions.py +2 -2
- gobby/config/features.py +7 -130
- gobby/config/skills.py +31 -0
- gobby/config/tasks.py +4 -28
- gobby/hooks/__init__.py +0 -13
- gobby/hooks/event_handlers.py +150 -8
- gobby/hooks/hook_manager.py +21 -3
- gobby/hooks/plugins.py +1 -1
- gobby/hooks/webhooks.py +1 -1
- gobby/install/gemini/hooks/hook_dispatcher.py +74 -15
- gobby/llm/resolver.py +3 -2
- gobby/mcp_proxy/importer.py +62 -4
- gobby/mcp_proxy/instructions.py +4 -2
- gobby/mcp_proxy/registries.py +22 -8
- gobby/mcp_proxy/services/recommendation.py +43 -11
- gobby/mcp_proxy/tools/agent_messaging.py +93 -44
- gobby/mcp_proxy/tools/agents.py +76 -740
- gobby/mcp_proxy/tools/artifacts.py +43 -9
- gobby/mcp_proxy/tools/clones.py +0 -385
- gobby/mcp_proxy/tools/memory.py +2 -2
- gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
- gobby/mcp_proxy/tools/sessions/_commits.py +239 -0
- gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
- gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
- gobby/mcp_proxy/tools/sessions/_handoff.py +503 -0
- gobby/mcp_proxy/tools/sessions/_messages.py +166 -0
- gobby/mcp_proxy/tools/skills/__init__.py +14 -29
- gobby/mcp_proxy/tools/spawn_agent.py +455 -0
- gobby/mcp_proxy/tools/tasks/_context.py +18 -0
- gobby/mcp_proxy/tools/tasks/_crud.py +13 -6
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +79 -30
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +1 -1
- gobby/mcp_proxy/tools/tasks/_session.py +22 -7
- gobby/mcp_proxy/tools/workflows.py +84 -34
- gobby/mcp_proxy/tools/worktrees.py +32 -350
- gobby/memory/extractor.py +15 -1
- gobby/memory/ingestion/__init__.py +5 -0
- gobby/memory/ingestion/multimodal.py +221 -0
- gobby/memory/manager.py +62 -283
- gobby/memory/search/__init__.py +10 -0
- gobby/memory/search/coordinator.py +248 -0
- gobby/memory/services/__init__.py +5 -0
- gobby/memory/services/crossref.py +142 -0
- gobby/prompts/loader.py +5 -2
- gobby/runner.py +13 -0
- gobby/servers/http.py +1 -4
- gobby/servers/routes/admin.py +14 -0
- gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
- gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
- gobby/servers/routes/mcp/endpoints/execution.py +568 -0
- gobby/servers/routes/mcp/endpoints/registry.py +378 -0
- gobby/servers/routes/mcp/endpoints/server.py +304 -0
- gobby/servers/routes/mcp/hooks.py +51 -4
- gobby/servers/routes/mcp/tools.py +48 -1506
- gobby/servers/websocket.py +57 -1
- gobby/sessions/analyzer.py +2 -2
- gobby/sessions/lifecycle.py +1 -1
- gobby/sessions/manager.py +9 -0
- gobby/sessions/processor.py +10 -0
- gobby/sessions/transcripts/base.py +1 -0
- gobby/sessions/transcripts/claude.py +15 -5
- gobby/sessions/transcripts/gemini.py +100 -34
- gobby/skills/parser.py +30 -2
- gobby/storage/database.py +9 -2
- gobby/storage/memories.py +32 -21
- gobby/storage/migrations.py +174 -368
- gobby/storage/sessions.py +45 -7
- gobby/storage/skills.py +80 -7
- gobby/storage/tasks/_lifecycle.py +18 -3
- gobby/sync/memories.py +1 -1
- gobby/tasks/external_validator.py +1 -1
- gobby/tasks/validation.py +22 -20
- gobby/tools/summarizer.py +91 -10
- gobby/utils/project_context.py +2 -3
- gobby/utils/status.py +13 -0
- gobby/workflows/actions.py +221 -1217
- gobby/workflows/artifact_actions.py +31 -0
- gobby/workflows/autonomous_actions.py +11 -0
- gobby/workflows/context_actions.py +50 -1
- gobby/workflows/detection_helpers.py +38 -24
- gobby/workflows/enforcement/__init__.py +47 -0
- gobby/workflows/enforcement/blocking.py +281 -0
- gobby/workflows/enforcement/commit_policy.py +283 -0
- gobby/workflows/enforcement/handlers.py +269 -0
- gobby/workflows/enforcement/task_policy.py +542 -0
- gobby/workflows/engine.py +93 -0
- gobby/workflows/evaluator.py +110 -0
- gobby/workflows/git_utils.py +106 -0
- gobby/workflows/hooks.py +41 -0
- gobby/workflows/llm_actions.py +30 -0
- gobby/workflows/mcp_actions.py +20 -1
- gobby/workflows/memory_actions.py +91 -0
- gobby/workflows/safe_evaluator.py +191 -0
- gobby/workflows/session_actions.py +44 -0
- gobby/workflows/state_actions.py +60 -1
- gobby/workflows/stop_signal_actions.py +55 -0
- gobby/workflows/summary_actions.py +217 -51
- gobby/workflows/task_sync_actions.py +347 -0
- gobby/workflows/todo_actions.py +34 -1
- gobby/workflows/webhook_actions.py +185 -0
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/METADATA +6 -1
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/RECORD +139 -163
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/WHEEL +1 -1
- gobby/adapters/codex.py +0 -1332
- gobby/cli/tui.py +0 -34
- gobby/install/claude/commands/gobby/bug.md +0 -51
- gobby/install/claude/commands/gobby/chore.md +0 -51
- gobby/install/claude/commands/gobby/epic.md +0 -52
- gobby/install/claude/commands/gobby/eval.md +0 -235
- gobby/install/claude/commands/gobby/feat.md +0 -49
- gobby/install/claude/commands/gobby/nit.md +0 -52
- gobby/install/claude/commands/gobby/ref.md +0 -52
- gobby/mcp_proxy/tools/session_messages.py +0 -1055
- gobby/prompts/defaults/expansion/system.md +0 -119
- gobby/prompts/defaults/expansion/user.md +0 -48
- gobby/prompts/defaults/external_validation/agent.md +0 -72
- gobby/prompts/defaults/external_validation/external.md +0 -63
- gobby/prompts/defaults/external_validation/spawn.md +0 -83
- gobby/prompts/defaults/external_validation/system.md +0 -6
- gobby/prompts/defaults/features/import_mcp.md +0 -22
- gobby/prompts/defaults/features/import_mcp_github.md +0 -17
- gobby/prompts/defaults/features/import_mcp_search.md +0 -16
- gobby/prompts/defaults/features/recommend_tools.md +0 -32
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
- gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
- gobby/prompts/defaults/features/server_description.md +0 -20
- gobby/prompts/defaults/features/server_description_system.md +0 -6
- gobby/prompts/defaults/features/task_description.md +0 -31
- gobby/prompts/defaults/features/task_description_system.md +0 -6
- gobby/prompts/defaults/features/tool_summary.md +0 -17
- gobby/prompts/defaults/features/tool_summary_system.md +0 -6
- gobby/prompts/defaults/handoff/compact.md +0 -63
- gobby/prompts/defaults/handoff/session_end.md +0 -57
- gobby/prompts/defaults/memory/extract.md +0 -61
- gobby/prompts/defaults/research/step.md +0 -58
- gobby/prompts/defaults/validation/criteria.md +0 -47
- gobby/prompts/defaults/validation/validate.md +0 -38
- gobby/storage/migrations_legacy.py +0 -1359
- gobby/tui/__init__.py +0 -5
- gobby/tui/api_client.py +0 -278
- gobby/tui/app.py +0 -329
- gobby/tui/screens/__init__.py +0 -25
- gobby/tui/screens/agents.py +0 -333
- gobby/tui/screens/chat.py +0 -450
- gobby/tui/screens/dashboard.py +0 -377
- gobby/tui/screens/memory.py +0 -305
- gobby/tui/screens/metrics.py +0 -231
- gobby/tui/screens/orchestrator.py +0 -903
- gobby/tui/screens/sessions.py +0 -412
- gobby/tui/screens/tasks.py +0 -440
- gobby/tui/screens/workflows.py +0 -289
- gobby/tui/screens/worktrees.py +0 -174
- gobby/tui/widgets/__init__.py +0 -21
- gobby/tui/widgets/chat.py +0 -210
- gobby/tui/widgets/conductor.py +0 -104
- gobby/tui/widgets/menu.py +0 -132
- gobby/tui/widgets/message_panel.py +0 -160
- gobby/tui/widgets/review_gate.py +0 -224
- gobby/tui/widgets/task_tree.py +0 -99
- gobby/tui/widgets/token_budget.py +0 -166
- gobby/tui/ws_client.py +0 -258
- gobby/workflows/task_enforcement_actions.py +0 -1343
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/entry_points.txt +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/licenses/LICENSE.md +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/top_level.txt +0 -0
|
@@ -6,9 +6,10 @@ Provides messaging capabilities between parent and child sessions:
|
|
|
6
6
|
- send_to_child: Parent sends message to a specific child
|
|
7
7
|
- poll_messages: Check for incoming messages
|
|
8
8
|
- mark_message_read: Mark a message as read
|
|
9
|
-
- broadcast_to_children: Send message to all
|
|
9
|
+
- broadcast_to_children: Send message to all children (active in database)
|
|
10
10
|
|
|
11
|
-
These tools resolve session relationships from
|
|
11
|
+
These tools resolve session relationships from the database (LocalSessionManager),
|
|
12
|
+
which is the authoritative source for parent_session_id relationships.
|
|
12
13
|
"""
|
|
13
14
|
|
|
14
15
|
from __future__ import annotations
|
|
@@ -17,9 +18,9 @@ import logging
|
|
|
17
18
|
from typing import TYPE_CHECKING, Any
|
|
18
19
|
|
|
19
20
|
if TYPE_CHECKING:
|
|
20
|
-
from gobby.agents.registry import RunningAgentRegistry
|
|
21
21
|
from gobby.mcp_proxy.tools.internal import InternalToolRegistry
|
|
22
22
|
from gobby.storage.inter_session_messages import InterSessionMessageManager
|
|
23
|
+
from gobby.storage.sessions import LocalSessionManager
|
|
23
24
|
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
25
26
|
|
|
@@ -27,7 +28,7 @@ logger = logging.getLogger(__name__)
|
|
|
27
28
|
def add_messaging_tools(
|
|
28
29
|
registry: InternalToolRegistry,
|
|
29
30
|
message_manager: InterSessionMessageManager,
|
|
30
|
-
|
|
31
|
+
session_manager: LocalSessionManager,
|
|
31
32
|
) -> None:
|
|
32
33
|
"""
|
|
33
34
|
Add inter-agent messaging tools to an existing registry.
|
|
@@ -35,12 +36,20 @@ def add_messaging_tools(
|
|
|
35
36
|
Args:
|
|
36
37
|
registry: The InternalToolRegistry to add tools to (typically gobby-agents)
|
|
37
38
|
message_manager: InterSessionMessageManager for persisting messages
|
|
38
|
-
|
|
39
|
+
session_manager: LocalSessionManager for resolving parent/child relationships
|
|
40
|
+
(database is the authoritative source for session relationships)
|
|
39
41
|
"""
|
|
42
|
+
from gobby.utils.project_context import get_project_context
|
|
43
|
+
|
|
44
|
+
def _resolve_session_id(ref: str) -> str:
|
|
45
|
+
"""Resolve session reference (#N, N, UUID, or prefix) to UUID."""
|
|
46
|
+
project_ctx = get_project_context()
|
|
47
|
+
project_id = project_ctx.get("id") if project_ctx else None
|
|
48
|
+
return session_manager.resolve_session_reference(ref, project_id)
|
|
40
49
|
|
|
41
50
|
@registry.tool(
|
|
42
51
|
name="send_to_parent",
|
|
43
|
-
description="Send a message from a child session to its parent session.",
|
|
52
|
+
description="Send a message from a child session to its parent session. Accepts #N, N, UUID, or prefix for session_id.",
|
|
44
53
|
)
|
|
45
54
|
async def send_to_parent(
|
|
46
55
|
session_id: str,
|
|
@@ -54,7 +63,7 @@ def add_messaging_tools(
|
|
|
54
63
|
or requests back to its parent session.
|
|
55
64
|
|
|
56
65
|
Args:
|
|
57
|
-
session_id:
|
|
66
|
+
session_id: Session reference (accepts #N, N, UUID, or prefix) for the current (child) session
|
|
58
67
|
content: Message content to send
|
|
59
68
|
priority: Message priority ("normal" or "urgent")
|
|
60
69
|
|
|
@@ -62,30 +71,41 @@ def add_messaging_tools(
|
|
|
62
71
|
Dict with success status and message details
|
|
63
72
|
"""
|
|
64
73
|
try:
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
# Resolve session_id to UUID (accepts #N, N, UUID, or prefix)
|
|
75
|
+
try:
|
|
76
|
+
resolved_session_id = _resolve_session_id(session_id)
|
|
77
|
+
except ValueError as e:
|
|
78
|
+
return {"success": False, "error": str(e)}
|
|
79
|
+
|
|
80
|
+
# Look up session in database (authoritative source for relationships)
|
|
81
|
+
session = session_manager.get(resolved_session_id)
|
|
82
|
+
if not session:
|
|
68
83
|
return {
|
|
69
84
|
"success": False,
|
|
70
|
-
"error": f"Session {
|
|
85
|
+
"error": f"Session {resolved_session_id} not found",
|
|
71
86
|
}
|
|
72
87
|
|
|
73
|
-
parent_session_id =
|
|
88
|
+
parent_session_id = session.parent_session_id
|
|
74
89
|
if not parent_session_id:
|
|
75
90
|
return {
|
|
76
91
|
"success": False,
|
|
77
|
-
"error": "No parent session
|
|
92
|
+
"error": "No parent session for this session",
|
|
78
93
|
}
|
|
79
94
|
|
|
80
95
|
# Create the message
|
|
81
96
|
msg = message_manager.create_message(
|
|
82
|
-
from_session=
|
|
97
|
+
from_session=resolved_session_id,
|
|
83
98
|
to_session=parent_session_id,
|
|
84
99
|
content=content,
|
|
85
100
|
priority=priority,
|
|
86
101
|
)
|
|
87
102
|
|
|
88
|
-
logger.info(
|
|
103
|
+
logger.info(
|
|
104
|
+
"Message sent from %s to parent %s: %s",
|
|
105
|
+
resolved_session_id,
|
|
106
|
+
parent_session_id,
|
|
107
|
+
msg.id,
|
|
108
|
+
)
|
|
89
109
|
|
|
90
110
|
return {
|
|
91
111
|
"success": True,
|
|
@@ -94,7 +114,7 @@ def add_messaging_tools(
|
|
|
94
114
|
}
|
|
95
115
|
|
|
96
116
|
except Exception as e:
|
|
97
|
-
logger.error(
|
|
117
|
+
logger.error("Failed to send message to parent: %s", e)
|
|
98
118
|
return {
|
|
99
119
|
"success": False,
|
|
100
120
|
"error": str(e),
|
|
@@ -102,7 +122,7 @@ def add_messaging_tools(
|
|
|
102
122
|
|
|
103
123
|
@registry.tool(
|
|
104
124
|
name="send_to_child",
|
|
105
|
-
description="Send a message from a parent session to a specific child session.",
|
|
125
|
+
description="Send a message from a parent session to a specific child session. Accepts #N, N, UUID, or prefix for session IDs.",
|
|
106
126
|
)
|
|
107
127
|
async def send_to_child(
|
|
108
128
|
parent_session_id: str,
|
|
@@ -117,8 +137,8 @@ def add_messaging_tools(
|
|
|
117
137
|
updates, or coordination messages to a spawned child.
|
|
118
138
|
|
|
119
139
|
Args:
|
|
120
|
-
parent_session_id:
|
|
121
|
-
child_session_id:
|
|
140
|
+
parent_session_id: Session reference (accepts #N, N, UUID, or prefix) for the parent (sender)
|
|
141
|
+
child_session_id: Session reference (accepts #N, N, UUID, or prefix) for the child (recipient)
|
|
122
142
|
content: Message content to send
|
|
123
143
|
priority: Message priority ("normal" or "urgent")
|
|
124
144
|
|
|
@@ -126,33 +146,43 @@ def add_messaging_tools(
|
|
|
126
146
|
Dict with success status and message details
|
|
127
147
|
"""
|
|
128
148
|
try:
|
|
129
|
-
#
|
|
130
|
-
|
|
131
|
-
|
|
149
|
+
# Resolve session IDs to UUIDs (accepts #N, N, UUID, or prefix)
|
|
150
|
+
try:
|
|
151
|
+
resolved_parent_id = _resolve_session_id(parent_session_id)
|
|
152
|
+
resolved_child_id = _resolve_session_id(child_session_id)
|
|
153
|
+
except ValueError as e:
|
|
154
|
+
return {"success": False, "error": str(e)}
|
|
155
|
+
|
|
156
|
+
# Verify the child exists in database and belongs to this parent
|
|
157
|
+
child_session = session_manager.get(resolved_child_id)
|
|
158
|
+
if not child_session:
|
|
132
159
|
return {
|
|
133
160
|
"success": False,
|
|
134
|
-
"error": f"Child session {
|
|
161
|
+
"error": f"Child session {resolved_child_id} not found",
|
|
135
162
|
}
|
|
136
163
|
|
|
137
|
-
if
|
|
164
|
+
if child_session.parent_session_id != resolved_parent_id:
|
|
138
165
|
return {
|
|
139
166
|
"success": False,
|
|
140
167
|
"error": (
|
|
141
|
-
f"Session {
|
|
142
|
-
f"Actual parent: {
|
|
168
|
+
f"Session {resolved_child_id} is not a child of {resolved_parent_id}. "
|
|
169
|
+
f"Actual parent: {child_session.parent_session_id}"
|
|
143
170
|
),
|
|
144
171
|
}
|
|
145
172
|
|
|
146
173
|
# Create the message
|
|
147
174
|
msg = message_manager.create_message(
|
|
148
|
-
from_session=
|
|
149
|
-
to_session=
|
|
175
|
+
from_session=resolved_parent_id,
|
|
176
|
+
to_session=resolved_child_id,
|
|
150
177
|
content=content,
|
|
151
178
|
priority=priority,
|
|
152
179
|
)
|
|
153
180
|
|
|
154
181
|
logger.info(
|
|
155
|
-
|
|
182
|
+
"Message sent from %s to child %s: %s",
|
|
183
|
+
resolved_parent_id,
|
|
184
|
+
resolved_child_id,
|
|
185
|
+
msg.id,
|
|
156
186
|
)
|
|
157
187
|
|
|
158
188
|
return {
|
|
@@ -161,7 +191,7 @@ def add_messaging_tools(
|
|
|
161
191
|
}
|
|
162
192
|
|
|
163
193
|
except Exception as e:
|
|
164
|
-
logger.error(
|
|
194
|
+
logger.error("Failed to send message to child: %s", e)
|
|
165
195
|
return {
|
|
166
196
|
"success": False,
|
|
167
197
|
"error": str(e),
|
|
@@ -169,7 +199,7 @@ def add_messaging_tools(
|
|
|
169
199
|
|
|
170
200
|
@registry.tool(
|
|
171
201
|
name="poll_messages",
|
|
172
|
-
description="Poll for messages sent to this session.",
|
|
202
|
+
description="Poll for messages sent to this session. Accepts #N, N, UUID, or prefix for session_id.",
|
|
173
203
|
)
|
|
174
204
|
async def poll_messages(
|
|
175
205
|
session_id: str,
|
|
@@ -182,15 +212,21 @@ def add_messaging_tools(
|
|
|
182
212
|
By default, returns only unread messages.
|
|
183
213
|
|
|
184
214
|
Args:
|
|
185
|
-
session_id:
|
|
215
|
+
session_id: Session reference (accepts #N, N, UUID, or prefix) to check messages for
|
|
186
216
|
unread_only: If True, only return unread messages (default: True)
|
|
187
217
|
|
|
188
218
|
Returns:
|
|
189
219
|
Dict with success status and list of messages
|
|
190
220
|
"""
|
|
191
221
|
try:
|
|
222
|
+
# Resolve session_id to UUID (accepts #N, N, UUID, or prefix)
|
|
223
|
+
try:
|
|
224
|
+
resolved_session_id = _resolve_session_id(session_id)
|
|
225
|
+
except ValueError as e:
|
|
226
|
+
return {"success": False, "error": str(e)}
|
|
227
|
+
|
|
192
228
|
messages = message_manager.get_messages(
|
|
193
|
-
to_session=
|
|
229
|
+
to_session=resolved_session_id,
|
|
194
230
|
unread_only=unread_only,
|
|
195
231
|
)
|
|
196
232
|
|
|
@@ -248,7 +284,7 @@ def add_messaging_tools(
|
|
|
248
284
|
|
|
249
285
|
@registry.tool(
|
|
250
286
|
name="broadcast_to_children",
|
|
251
|
-
description="Broadcast a message to all
|
|
287
|
+
description="Broadcast a message to all active child sessions. Accepts #N, N, UUID, or prefix for session_id.",
|
|
252
288
|
)
|
|
253
289
|
async def broadcast_to_children(
|
|
254
290
|
parent_session_id: str,
|
|
@@ -256,13 +292,14 @@ def add_messaging_tools(
|
|
|
256
292
|
priority: str = "normal",
|
|
257
293
|
) -> dict[str, Any]:
|
|
258
294
|
"""
|
|
259
|
-
Broadcast a message to all
|
|
295
|
+
Broadcast a message to all active children.
|
|
260
296
|
|
|
261
|
-
Send the same message to all child sessions spawned by this parent
|
|
297
|
+
Send the same message to all child sessions spawned by this parent
|
|
298
|
+
that are currently active in the database.
|
|
262
299
|
Useful for coordination or shutdown signals.
|
|
263
300
|
|
|
264
301
|
Args:
|
|
265
|
-
parent_session_id:
|
|
302
|
+
parent_session_id: Session reference (accepts #N, N, UUID, or prefix) for the parent
|
|
266
303
|
content: Message content to broadcast
|
|
267
304
|
priority: Message priority ("normal" or "urgent")
|
|
268
305
|
|
|
@@ -270,13 +307,22 @@ def add_messaging_tools(
|
|
|
270
307
|
Dict with success status and count of messages sent
|
|
271
308
|
"""
|
|
272
309
|
try:
|
|
273
|
-
|
|
310
|
+
# Resolve session_id to UUID (accepts #N, N, UUID, or prefix)
|
|
311
|
+
try:
|
|
312
|
+
resolved_parent_id = _resolve_session_id(parent_session_id)
|
|
313
|
+
except ValueError as e:
|
|
314
|
+
return {"success": False, "error": str(e)}
|
|
315
|
+
|
|
316
|
+
# Get all children from database
|
|
317
|
+
all_children = session_manager.find_children(resolved_parent_id)
|
|
318
|
+
# Filter to active children only
|
|
319
|
+
children = [c for c in all_children if c.status == "active"]
|
|
274
320
|
|
|
275
321
|
if not children:
|
|
276
322
|
return {
|
|
277
323
|
"success": True,
|
|
278
324
|
"sent_count": 0,
|
|
279
|
-
"message": "No
|
|
325
|
+
"message": "No active children found",
|
|
280
326
|
}
|
|
281
327
|
|
|
282
328
|
sent_count = 0
|
|
@@ -285,14 +331,14 @@ def add_messaging_tools(
|
|
|
285
331
|
for child in children:
|
|
286
332
|
try:
|
|
287
333
|
message_manager.create_message(
|
|
288
|
-
from_session=
|
|
289
|
-
to_session=child.
|
|
334
|
+
from_session=resolved_parent_id,
|
|
335
|
+
to_session=child.id,
|
|
290
336
|
content=content,
|
|
291
337
|
priority=priority,
|
|
292
338
|
)
|
|
293
339
|
sent_count += 1
|
|
294
340
|
except Exception as e:
|
|
295
|
-
errors.append(f"{child.
|
|
341
|
+
errors.append(f"{child.id}: {e}")
|
|
296
342
|
|
|
297
343
|
result: dict[str, Any] = {
|
|
298
344
|
"success": True,
|
|
@@ -304,13 +350,16 @@ def add_messaging_tools(
|
|
|
304
350
|
result["errors"] = errors
|
|
305
351
|
|
|
306
352
|
logger.info(
|
|
307
|
-
|
|
353
|
+
"Broadcast from %s sent to %d/%d children",
|
|
354
|
+
resolved_parent_id,
|
|
355
|
+
sent_count,
|
|
356
|
+
len(children),
|
|
308
357
|
)
|
|
309
358
|
|
|
310
359
|
return result
|
|
311
360
|
|
|
312
361
|
except Exception as e:
|
|
313
|
-
logger.error(
|
|
362
|
+
logger.error("Failed to broadcast to children: %s", e)
|
|
314
363
|
return {
|
|
315
364
|
"success": False,
|
|
316
365
|
"error": str(e),
|