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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type definitions and data classes for Codex adapter.
|
|
3
|
+
|
|
4
|
+
Extracted from codex.py as part of Phase 3 Strangler Fig decomposition.
|
|
5
|
+
These types are used throughout the Codex adapter implementation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CodexConnectionState(Enum):
|
|
17
|
+
"""Connection state for the Codex app-server."""
|
|
18
|
+
|
|
19
|
+
DISCONNECTED = "disconnected"
|
|
20
|
+
CONNECTING = "connecting"
|
|
21
|
+
CONNECTED = "connected"
|
|
22
|
+
ERROR = "error"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class CodexThread:
|
|
27
|
+
"""Represents a Codex conversation thread."""
|
|
28
|
+
|
|
29
|
+
id: str
|
|
30
|
+
preview: str = ""
|
|
31
|
+
model_provider: str = "openai"
|
|
32
|
+
created_at: int = 0
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class CodexTurn:
|
|
37
|
+
"""Represents a turn in a Codex conversation."""
|
|
38
|
+
|
|
39
|
+
id: str
|
|
40
|
+
thread_id: str
|
|
41
|
+
status: str = "pending"
|
|
42
|
+
items: list[dict[str, Any]] = field(default_factory=list)
|
|
43
|
+
error: str | None = None
|
|
44
|
+
usage: dict[str, int] | None = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class CodexItem:
|
|
49
|
+
"""Represents an item (message, tool call, etc.) in a turn."""
|
|
50
|
+
|
|
51
|
+
id: str
|
|
52
|
+
type: str # "reasoning", "agent_message", "command_execution", "user_message", etc.
|
|
53
|
+
content: str = ""
|
|
54
|
+
status: str = "pending"
|
|
55
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Type alias for notification handlers
|
|
59
|
+
NotificationHandler = Callable[[str, dict[str, Any]], None]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
__all__ = [
|
|
63
|
+
"CodexConnectionState",
|
|
64
|
+
"CodexThread",
|
|
65
|
+
"CodexTurn",
|
|
66
|
+
"CodexItem",
|
|
67
|
+
"NotificationHandler",
|
|
68
|
+
]
|
gobby/adapters/gemini.py
CHANGED
|
@@ -76,21 +76,39 @@ class GeminiAdapter(BaseAdapter):
|
|
|
76
76
|
|
|
77
77
|
# Tool name mapping: Gemini tool names -> normalized names
|
|
78
78
|
# Gemini uses different tool names than Claude Code
|
|
79
|
+
# This enables workflows to use Claude Code naming conventions
|
|
79
80
|
TOOL_MAP: dict[str, str] = {
|
|
81
|
+
# Shell/Bash
|
|
80
82
|
"run_shell_command": "Bash",
|
|
81
83
|
"RunShellCommand": "Bash",
|
|
84
|
+
"ShellTool": "Bash",
|
|
85
|
+
# File read
|
|
82
86
|
"read_file": "Read",
|
|
83
87
|
"ReadFile": "Read",
|
|
84
88
|
"ReadFileTool": "Read",
|
|
89
|
+
# File write
|
|
85
90
|
"write_file": "Write",
|
|
86
91
|
"WriteFile": "Write",
|
|
87
92
|
"WriteFileTool": "Write",
|
|
93
|
+
# File edit
|
|
88
94
|
"edit_file": "Edit",
|
|
89
95
|
"EditFile": "Edit",
|
|
90
96
|
"EditFileTool": "Edit",
|
|
97
|
+
# Search/Glob/Grep
|
|
91
98
|
"GlobTool": "Glob",
|
|
92
99
|
"GrepTool": "Grep",
|
|
93
|
-
"
|
|
100
|
+
"search_file_content": "Grep",
|
|
101
|
+
"SearchText": "Grep",
|
|
102
|
+
# MCP tools (Gobby MCP server)
|
|
103
|
+
"call_tool": "mcp__gobby__call_tool",
|
|
104
|
+
"list_mcp_servers": "mcp__gobby__list_mcp_servers",
|
|
105
|
+
"list_tools": "mcp__gobby__list_tools",
|
|
106
|
+
"get_tool_schema": "mcp__gobby__get_tool_schema",
|
|
107
|
+
"search_tools": "mcp__gobby__search_tools",
|
|
108
|
+
"recommend_tools": "mcp__gobby__recommend_tools",
|
|
109
|
+
# Skill and agent tools
|
|
110
|
+
"activate_skill": "Skill",
|
|
111
|
+
"delegate_to_agent": "Task",
|
|
94
112
|
}
|
|
95
113
|
|
|
96
114
|
def __init__(self, hook_manager: "HookManager | None" = None):
|
|
@@ -135,6 +153,55 @@ class GeminiAdapter(BaseAdapter):
|
|
|
135
153
|
"""
|
|
136
154
|
return self.TOOL_MAP.get(gemini_tool_name, gemini_tool_name)
|
|
137
155
|
|
|
156
|
+
def _normalize_event_data(self, input_data: dict[str, Any]) -> dict[str, Any]:
|
|
157
|
+
"""Normalize Gemini event data for CLI-agnostic processing.
|
|
158
|
+
|
|
159
|
+
This method enriches the input_data with normalized fields so downstream
|
|
160
|
+
code doesn't need to handle Gemini-specific formats.
|
|
161
|
+
|
|
162
|
+
Normalizations performed:
|
|
163
|
+
1. mcp_context.server_name/tool_name → mcp_server/mcp_tool (top-level)
|
|
164
|
+
2. tool_response → tool_output
|
|
165
|
+
3. function_name → tool_name (if not already present)
|
|
166
|
+
4. parameters/args → tool_input (if not already present)
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
input_data: Raw input data from Gemini CLI
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Enriched data dict with normalized fields added
|
|
173
|
+
"""
|
|
174
|
+
# Start with a copy to avoid mutating original
|
|
175
|
+
data = dict(input_data)
|
|
176
|
+
|
|
177
|
+
# 1. Flatten mcp_context to top-level mcp_server/mcp_tool
|
|
178
|
+
mcp_context = data.get("mcp_context")
|
|
179
|
+
if mcp_context and isinstance(mcp_context, dict):
|
|
180
|
+
if "mcp_server" not in data:
|
|
181
|
+
data["mcp_server"] = mcp_context.get("server_name")
|
|
182
|
+
if "mcp_tool" not in data:
|
|
183
|
+
data["mcp_tool"] = mcp_context.get("tool_name")
|
|
184
|
+
|
|
185
|
+
# 2. Normalize tool_response → tool_output
|
|
186
|
+
if "tool_response" in data and "tool_output" not in data:
|
|
187
|
+
data["tool_output"] = data["tool_response"]
|
|
188
|
+
|
|
189
|
+
# 3. Normalize function_name → tool_name
|
|
190
|
+
if "function_name" in data and "tool_name" not in data:
|
|
191
|
+
data["tool_name"] = self.normalize_tool_name(data["function_name"])
|
|
192
|
+
elif "tool_name" in data:
|
|
193
|
+
# Normalize existing tool_name
|
|
194
|
+
data["tool_name"] = self.normalize_tool_name(data["tool_name"])
|
|
195
|
+
|
|
196
|
+
# 4. Normalize parameters/args → tool_input
|
|
197
|
+
if "tool_input" not in data:
|
|
198
|
+
if "parameters" in data:
|
|
199
|
+
data["tool_input"] = data["parameters"]
|
|
200
|
+
elif "args" in data:
|
|
201
|
+
data["tool_input"] = data["args"]
|
|
202
|
+
|
|
203
|
+
return data
|
|
204
|
+
|
|
138
205
|
def translate_to_hook_event(self, native_event: dict[str, Any]) -> HookEvent:
|
|
139
206
|
"""Convert Gemini CLI native event to unified HookEvent.
|
|
140
207
|
|
|
@@ -202,6 +269,10 @@ class GeminiAdapter(BaseAdapter):
|
|
|
202
269
|
else:
|
|
203
270
|
metadata = {}
|
|
204
271
|
|
|
272
|
+
# Normalize event data for CLI-agnostic processing
|
|
273
|
+
# This allows downstream code to use consistent field names
|
|
274
|
+
normalized_data = self._normalize_event_data(input_data)
|
|
275
|
+
|
|
205
276
|
return HookEvent(
|
|
206
277
|
event_type=event_type,
|
|
207
278
|
session_id=session_id,
|
|
@@ -209,7 +280,7 @@ class GeminiAdapter(BaseAdapter):
|
|
|
209
280
|
timestamp=timestamp,
|
|
210
281
|
machine_id=machine_id,
|
|
211
282
|
cwd=input_data.get("cwd"),
|
|
212
|
-
data=
|
|
283
|
+
data=normalized_data,
|
|
213
284
|
metadata=metadata,
|
|
214
285
|
)
|
|
215
286
|
|
|
@@ -254,46 +325,77 @@ class GeminiAdapter(BaseAdapter):
|
|
|
254
325
|
if response.context:
|
|
255
326
|
hook_specific["additionalContext"] = response.context
|
|
256
327
|
|
|
257
|
-
# Add session/terminal context for
|
|
258
|
-
|
|
328
|
+
# Add session/terminal context for hooks that support additionalContext
|
|
329
|
+
# Parity with Claude Code: inject on SessionStart, BeforeAgent, BeforeTool, AfterTool
|
|
330
|
+
hooks_with_context = {"SessionStart", "BeforeAgent", "BeforeTool", "AfterTool"}
|
|
331
|
+
if hook_type in hooks_with_context and response.metadata:
|
|
259
332
|
session_id = response.metadata.get("session_id")
|
|
333
|
+
session_ref = response.metadata.get("session_ref")
|
|
334
|
+
external_id = response.metadata.get("external_id")
|
|
335
|
+
is_first_hook = response.metadata.get("_first_hook_for_session", False)
|
|
336
|
+
|
|
260
337
|
if session_id:
|
|
261
338
|
hook_event_name = self.HOOK_EVENT_NAME_MAP.get(hook_type, "Unknown")
|
|
262
|
-
|
|
263
|
-
if
|
|
264
|
-
|
|
265
|
-
|
|
339
|
+
|
|
340
|
+
if is_first_hook:
|
|
341
|
+
# First hook: inject full metadata (~60-100 tokens)
|
|
342
|
+
context_lines = []
|
|
343
|
+
if session_ref:
|
|
344
|
+
context_lines.append(f"Gobby Session ID: {session_ref} (or {session_id})")
|
|
345
|
+
else:
|
|
346
|
+
context_lines.append(f"Gobby Session ID: {session_id}")
|
|
347
|
+
if external_id:
|
|
348
|
+
context_lines.append(
|
|
349
|
+
f"CLI-Specific Session ID (external_id): {external_id}"
|
|
350
|
+
)
|
|
351
|
+
if response.metadata.get("parent_session_id"):
|
|
352
|
+
context_lines.append(
|
|
353
|
+
f"parent_session_id: {response.metadata['parent_session_id']}"
|
|
354
|
+
)
|
|
355
|
+
if response.metadata.get("machine_id"):
|
|
356
|
+
context_lines.append(f"machine_id: {response.metadata['machine_id']}")
|
|
357
|
+
if response.metadata.get("project_id"):
|
|
358
|
+
context_lines.append(f"project_id: {response.metadata['project_id']}")
|
|
359
|
+
# Add terminal context (non-null values only)
|
|
360
|
+
if response.metadata.get("terminal_term_program"):
|
|
361
|
+
context_lines.append(
|
|
362
|
+
f"terminal: {response.metadata['terminal_term_program']}"
|
|
363
|
+
)
|
|
364
|
+
if response.metadata.get("terminal_tty"):
|
|
365
|
+
context_lines.append(f"tty: {response.metadata['terminal_tty']}")
|
|
366
|
+
if response.metadata.get("terminal_parent_pid"):
|
|
367
|
+
context_lines.append(
|
|
368
|
+
f"parent_pid: {response.metadata['terminal_parent_pid']}"
|
|
369
|
+
)
|
|
370
|
+
# Add terminal-specific session IDs
|
|
371
|
+
for key in [
|
|
372
|
+
"terminal_iterm_session_id",
|
|
373
|
+
"terminal_term_session_id",
|
|
374
|
+
"terminal_kitty_window_id",
|
|
375
|
+
"terminal_tmux_pane",
|
|
376
|
+
"terminal_vscode_terminal_id",
|
|
377
|
+
"terminal_alacritty_socket",
|
|
378
|
+
]:
|
|
379
|
+
if response.metadata.get(key):
|
|
380
|
+
friendly_name = key.replace("terminal_", "").replace("_", " ")
|
|
381
|
+
context_lines.append(f"{friendly_name}: {response.metadata[key]}")
|
|
382
|
+
|
|
383
|
+
hook_specific["hookEventName"] = hook_event_name
|
|
384
|
+
# Append to existing additionalContext if present
|
|
385
|
+
existing = hook_specific.get("additionalContext", "")
|
|
386
|
+
new_context = "\n".join(context_lines)
|
|
387
|
+
hook_specific["additionalContext"] = (
|
|
388
|
+
f"{existing}\n{new_context}" if existing else new_context
|
|
266
389
|
)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if response.metadata.get("terminal_parent_pid"):
|
|
277
|
-
context_lines.append(f"parent_pid: {response.metadata['terminal_parent_pid']}")
|
|
278
|
-
# Add terminal-specific session IDs
|
|
279
|
-
for key in [
|
|
280
|
-
"terminal_iterm_session_id",
|
|
281
|
-
"terminal_term_session_id",
|
|
282
|
-
"terminal_kitty_window_id",
|
|
283
|
-
"terminal_tmux_pane",
|
|
284
|
-
"terminal_vscode_terminal_id",
|
|
285
|
-
"terminal_alacritty_socket",
|
|
286
|
-
]:
|
|
287
|
-
if response.metadata.get(key):
|
|
288
|
-
friendly_name = key.replace("terminal_", "").replace("_", " ")
|
|
289
|
-
context_lines.append(f"{friendly_name}: {response.metadata[key]}")
|
|
290
|
-
hook_specific["hookEventName"] = hook_event_name
|
|
291
|
-
# Append to existing additionalContext if present
|
|
292
|
-
existing = hook_specific.get("additionalContext", "")
|
|
293
|
-
new_context = "\n".join(context_lines)
|
|
294
|
-
hook_specific["additionalContext"] = (
|
|
295
|
-
f"{existing}\n{new_context}" if existing else new_context
|
|
296
|
-
)
|
|
390
|
+
else:
|
|
391
|
+
# Subsequent hooks: inject minimal session ref only (~8 tokens)
|
|
392
|
+
if session_ref:
|
|
393
|
+
hook_specific["hookEventName"] = hook_event_name
|
|
394
|
+
existing = hook_specific.get("additionalContext", "")
|
|
395
|
+
minimal_context = f"Gobby Session ID: {session_ref}"
|
|
396
|
+
hook_specific["additionalContext"] = (
|
|
397
|
+
f"{existing}\n{minimal_context}" if existing else minimal_context
|
|
398
|
+
)
|
|
297
399
|
|
|
298
400
|
# Handle BeforeModel-specific output (llm_request modification)
|
|
299
401
|
if hook_type == "BeforeModel" and response.modify_args:
|
gobby/agents/definitions.py
CHANGED
|
@@ -8,11 +8,12 @@ lifecycle behavior, solving recursion loops in delegation.
|
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
11
|
+
from typing import Any, Literal
|
|
12
12
|
|
|
13
13
|
import yaml
|
|
14
14
|
from pydantic import BaseModel, Field
|
|
15
15
|
|
|
16
|
+
from gobby.agents.sandbox import SandboxConfig
|
|
16
17
|
from gobby.utils.project_context import get_project_context
|
|
17
18
|
|
|
18
19
|
logger = logging.getLogger(__name__)
|
|
@@ -29,6 +30,15 @@ class AgentDefinition(BaseModel):
|
|
|
29
30
|
# Execution parameters
|
|
30
31
|
model: str | None = None
|
|
31
32
|
mode: str = "headless" # Default to headless for stability
|
|
33
|
+
provider: str = "claude" # Provider: claude, gemini, codex
|
|
34
|
+
|
|
35
|
+
# Isolation configuration
|
|
36
|
+
isolation: Literal["current", "worktree", "clone"] | None = None
|
|
37
|
+
branch_prefix: str | None = None
|
|
38
|
+
base_branch: str = "main"
|
|
39
|
+
|
|
40
|
+
# Sandbox configuration
|
|
41
|
+
sandbox: SandboxConfig | None = None
|
|
32
42
|
|
|
33
43
|
# Workflow configuration
|
|
34
44
|
workflow: str | None = None
|