shotgun-sh 0.1.9__py3-none-any.whl → 0.2.11__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.
Potentially problematic release.
This version of shotgun-sh might be problematic. Click here for more details.
- shotgun/agents/agent_manager.py +761 -52
- shotgun/agents/common.py +80 -75
- shotgun/agents/config/constants.py +21 -10
- shotgun/agents/config/manager.py +322 -97
- shotgun/agents/config/models.py +114 -84
- shotgun/agents/config/provider.py +232 -88
- shotgun/agents/context_analyzer/__init__.py +28 -0
- shotgun/agents/context_analyzer/analyzer.py +471 -0
- shotgun/agents/context_analyzer/constants.py +9 -0
- shotgun/agents/context_analyzer/formatter.py +115 -0
- shotgun/agents/context_analyzer/models.py +212 -0
- shotgun/agents/conversation_history.py +125 -2
- shotgun/agents/conversation_manager.py +57 -19
- shotgun/agents/export.py +6 -7
- shotgun/agents/history/compaction.py +23 -3
- shotgun/agents/history/context_extraction.py +93 -6
- shotgun/agents/history/history_processors.py +179 -11
- shotgun/agents/history/token_counting/__init__.py +31 -0
- shotgun/agents/history/token_counting/anthropic.py +127 -0
- shotgun/agents/history/token_counting/base.py +78 -0
- shotgun/agents/history/token_counting/openai.py +90 -0
- shotgun/agents/history/token_counting/sentencepiece_counter.py +127 -0
- shotgun/agents/history/token_counting/tokenizer_cache.py +92 -0
- shotgun/agents/history/token_counting/utils.py +144 -0
- shotgun/agents/history/token_estimation.py +12 -12
- shotgun/agents/llm.py +62 -0
- shotgun/agents/models.py +59 -4
- shotgun/agents/plan.py +6 -7
- shotgun/agents/research.py +7 -8
- shotgun/agents/specify.py +6 -7
- shotgun/agents/tasks.py +6 -7
- shotgun/agents/tools/__init__.py +0 -2
- shotgun/agents/tools/codebase/codebase_shell.py +6 -0
- shotgun/agents/tools/codebase/directory_lister.py +6 -0
- shotgun/agents/tools/codebase/file_read.py +11 -2
- shotgun/agents/tools/codebase/query_graph.py +6 -0
- shotgun/agents/tools/codebase/retrieve_code.py +6 -0
- shotgun/agents/tools/file_management.py +82 -16
- shotgun/agents/tools/registry.py +217 -0
- shotgun/agents/tools/web_search/__init__.py +55 -16
- shotgun/agents/tools/web_search/anthropic.py +76 -51
- shotgun/agents/tools/web_search/gemini.py +50 -27
- shotgun/agents/tools/web_search/openai.py +26 -17
- shotgun/agents/tools/web_search/utils.py +2 -2
- shotgun/agents/usage_manager.py +164 -0
- shotgun/api_endpoints.py +15 -0
- shotgun/cli/clear.py +53 -0
- shotgun/cli/codebase/commands.py +71 -2
- shotgun/cli/compact.py +186 -0
- shotgun/cli/config.py +41 -67
- shotgun/cli/context.py +111 -0
- shotgun/cli/export.py +1 -1
- shotgun/cli/feedback.py +50 -0
- shotgun/cli/models.py +3 -2
- shotgun/cli/plan.py +1 -1
- shotgun/cli/research.py +1 -1
- shotgun/cli/specify.py +1 -1
- shotgun/cli/tasks.py +1 -1
- shotgun/cli/update.py +18 -5
- shotgun/codebase/core/change_detector.py +5 -3
- shotgun/codebase/core/code_retrieval.py +4 -2
- shotgun/codebase/core/ingestor.py +169 -19
- shotgun/codebase/core/manager.py +177 -13
- shotgun/codebase/core/nl_query.py +1 -1
- shotgun/codebase/models.py +28 -3
- shotgun/codebase/service.py +14 -2
- shotgun/exceptions.py +32 -0
- shotgun/llm_proxy/__init__.py +19 -0
- shotgun/llm_proxy/clients.py +44 -0
- shotgun/llm_proxy/constants.py +15 -0
- shotgun/logging_config.py +18 -27
- shotgun/main.py +91 -4
- shotgun/posthog_telemetry.py +87 -40
- shotgun/prompts/agents/export.j2 +18 -1
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +5 -1
- shotgun/prompts/agents/partials/interactive_mode.j2 +24 -7
- shotgun/prompts/agents/plan.j2 +1 -1
- shotgun/prompts/agents/research.j2 +1 -1
- shotgun/prompts/agents/specify.j2 +270 -3
- shotgun/prompts/agents/state/system_state.j2 +4 -0
- shotgun/prompts/agents/tasks.j2 +1 -1
- shotgun/prompts/codebase/partials/cypher_rules.j2 +13 -0
- shotgun/prompts/loader.py +2 -2
- shotgun/prompts/tools/web_search.j2 +14 -0
- shotgun/sdk/codebase.py +60 -2
- shotgun/sentry_telemetry.py +28 -21
- shotgun/settings.py +238 -0
- shotgun/shotgun_web/__init__.py +19 -0
- shotgun/shotgun_web/client.py +138 -0
- shotgun/shotgun_web/constants.py +21 -0
- shotgun/shotgun_web/models.py +47 -0
- shotgun/telemetry.py +24 -36
- shotgun/tui/app.py +275 -23
- shotgun/tui/commands/__init__.py +1 -1
- shotgun/tui/components/context_indicator.py +179 -0
- shotgun/tui/components/mode_indicator.py +70 -0
- shotgun/tui/components/status_bar.py +48 -0
- shotgun/tui/components/vertical_tail.py +6 -0
- shotgun/tui/containers.py +91 -0
- shotgun/tui/dependencies.py +39 -0
- shotgun/tui/filtered_codebase_service.py +46 -0
- shotgun/tui/protocols.py +45 -0
- shotgun/tui/screens/chat/__init__.py +5 -0
- shotgun/tui/screens/chat/chat.tcss +54 -0
- shotgun/tui/screens/chat/chat_screen.py +1234 -0
- shotgun/tui/screens/chat/codebase_index_prompt_screen.py +64 -0
- shotgun/tui/screens/chat/codebase_index_selection.py +12 -0
- shotgun/tui/screens/chat/help_text.py +40 -0
- shotgun/tui/screens/chat/prompt_history.py +48 -0
- shotgun/tui/screens/chat.tcss +11 -0
- shotgun/tui/screens/chat_screen/command_providers.py +226 -11
- shotgun/tui/screens/chat_screen/history/__init__.py +22 -0
- shotgun/tui/screens/chat_screen/history/agent_response.py +66 -0
- shotgun/tui/screens/chat_screen/history/chat_history.py +116 -0
- shotgun/tui/screens/chat_screen/history/formatters.py +115 -0
- shotgun/tui/screens/chat_screen/history/partial_response.py +43 -0
- shotgun/tui/screens/chat_screen/history/user_question.py +42 -0
- shotgun/tui/screens/confirmation_dialog.py +151 -0
- shotgun/tui/screens/feedback.py +193 -0
- shotgun/tui/screens/github_issue.py +102 -0
- shotgun/tui/screens/model_picker.py +352 -0
- shotgun/tui/screens/onboarding.py +431 -0
- shotgun/tui/screens/pipx_migration.py +153 -0
- shotgun/tui/screens/provider_config.py +156 -39
- shotgun/tui/screens/shotgun_auth.py +295 -0
- shotgun/tui/screens/welcome.py +198 -0
- shotgun/tui/services/__init__.py +5 -0
- shotgun/tui/services/conversation_service.py +184 -0
- shotgun/tui/state/__init__.py +7 -0
- shotgun/tui/state/processing_state.py +185 -0
- shotgun/tui/utils/mode_progress.py +14 -7
- shotgun/tui/widgets/__init__.py +5 -0
- shotgun/tui/widgets/widget_coordinator.py +262 -0
- shotgun/utils/datetime_utils.py +77 -0
- shotgun/utils/env_utils.py +13 -0
- shotgun/utils/file_system_utils.py +22 -2
- shotgun/utils/marketing.py +110 -0
- shotgun/utils/source_detection.py +16 -0
- shotgun/utils/update_checker.py +73 -21
- shotgun_sh-0.2.11.dist-info/METADATA +130 -0
- shotgun_sh-0.2.11.dist-info/RECORD +194 -0
- {shotgun_sh-0.1.9.dist-info → shotgun_sh-0.2.11.dist-info}/entry_points.txt +1 -0
- {shotgun_sh-0.1.9.dist-info → shotgun_sh-0.2.11.dist-info}/licenses/LICENSE +1 -1
- shotgun/agents/history/token_counting.py +0 -429
- shotgun/agents/tools/user_interaction.py +0 -37
- shotgun/tui/screens/chat.py +0 -818
- shotgun/tui/screens/chat_screen/history.py +0 -222
- shotgun_sh-0.1.9.dist-info/METADATA +0 -466
- shotgun_sh-0.1.9.dist-info/RECORD +0 -131
- {shotgun_sh-0.1.9.dist-info → shotgun_sh-0.2.11.dist-info}/WHEEL +0 -0
shotgun/agents/common.py
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
"""Common utilities for agent creation and management."""
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
from collections.abc import Callable
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
7
|
+
import aiofiles
|
|
8
8
|
from pydantic_ai import (
|
|
9
9
|
Agent,
|
|
10
|
-
DeferredToolRequests,
|
|
11
|
-
DeferredToolResults,
|
|
12
10
|
RunContext,
|
|
13
11
|
UsageLimits,
|
|
14
12
|
)
|
|
@@ -18,21 +16,20 @@ from pydantic_ai.messages import (
|
|
|
18
16
|
ModelRequest,
|
|
19
17
|
)
|
|
20
18
|
|
|
21
|
-
from shotgun.agents.config import ProviderType,
|
|
22
|
-
from shotgun.agents.models import AgentType
|
|
19
|
+
from shotgun.agents.config import ProviderType, get_provider_model
|
|
20
|
+
from shotgun.agents.models import AgentResponse, AgentType
|
|
23
21
|
from shotgun.logging_config import get_logger
|
|
24
22
|
from shotgun.prompts import PromptLoader
|
|
25
23
|
from shotgun.sdk.services import get_codebase_service
|
|
26
24
|
from shotgun.utils import ensure_shotgun_directory_exists
|
|
25
|
+
from shotgun.utils.datetime_utils import get_datetime_context
|
|
27
26
|
from shotgun.utils.file_system_utils import get_shotgun_base_path
|
|
28
27
|
|
|
29
28
|
from .history import token_limit_compactor
|
|
30
|
-
from .history.compaction import apply_persistent_compaction
|
|
31
29
|
from .messages import AgentSystemPrompt, SystemStatusPrompt
|
|
32
30
|
from .models import AgentDeps, AgentRuntimeOptions, PipelineConfigEntry
|
|
33
31
|
from .tools import (
|
|
34
32
|
append_file,
|
|
35
|
-
ask_user,
|
|
36
33
|
codebase_shell,
|
|
37
34
|
directory_lister,
|
|
38
35
|
file_read,
|
|
@@ -72,7 +69,10 @@ async def add_system_status_message(
|
|
|
72
69
|
existing_files = get_agent_existing_files(deps.agent_mode)
|
|
73
70
|
|
|
74
71
|
# Extract table of contents from the agent's markdown file
|
|
75
|
-
markdown_toc = extract_markdown_toc(deps.agent_mode)
|
|
72
|
+
markdown_toc = await extract_markdown_toc(deps.agent_mode)
|
|
73
|
+
|
|
74
|
+
# Get current datetime with timezone information
|
|
75
|
+
dt_context = get_datetime_context()
|
|
76
76
|
|
|
77
77
|
system_state = prompt_loader.render(
|
|
78
78
|
"agents/state/system_state.j2",
|
|
@@ -80,6 +80,9 @@ async def add_system_status_message(
|
|
|
80
80
|
is_tui_context=deps.is_tui_context,
|
|
81
81
|
existing_files=existing_files,
|
|
82
82
|
markdown_toc=markdown_toc,
|
|
83
|
+
current_datetime=dt_context.datetime_formatted,
|
|
84
|
+
timezone_name=dt_context.timezone_name,
|
|
85
|
+
utc_offset=dt_context.utc_offset,
|
|
83
86
|
)
|
|
84
87
|
|
|
85
88
|
message_history.append(
|
|
@@ -92,14 +95,14 @@ async def add_system_status_message(
|
|
|
92
95
|
return message_history
|
|
93
96
|
|
|
94
97
|
|
|
95
|
-
def create_base_agent(
|
|
98
|
+
async def create_base_agent(
|
|
96
99
|
system_prompt_fn: Callable[[RunContext[AgentDeps]], str],
|
|
97
100
|
agent_runtime_options: AgentRuntimeOptions,
|
|
98
101
|
load_codebase_understanding_tools: bool = True,
|
|
99
102
|
additional_tools: list[Any] | None = None,
|
|
100
103
|
provider: ProviderType | None = None,
|
|
101
104
|
agent_mode: AgentType | None = None,
|
|
102
|
-
) -> tuple[Agent[AgentDeps,
|
|
105
|
+
) -> tuple[Agent[AgentDeps, AgentResponse], AgentDeps]:
|
|
103
106
|
"""Create a base agent with common configuration.
|
|
104
107
|
|
|
105
108
|
Args:
|
|
@@ -115,14 +118,13 @@ def create_base_agent(
|
|
|
115
118
|
"""
|
|
116
119
|
ensure_shotgun_directory_exists()
|
|
117
120
|
|
|
118
|
-
# Get configured model or fall back to
|
|
121
|
+
# Get configured model or fall back to first available provider
|
|
119
122
|
try:
|
|
120
|
-
model_config = get_provider_model(provider)
|
|
121
|
-
|
|
122
|
-
provider_name = provider or config_manager.load().default_provider
|
|
123
|
+
model_config = await get_provider_model(provider)
|
|
124
|
+
provider_name = model_config.provider
|
|
123
125
|
logger.debug(
|
|
124
126
|
"🤖 Creating agent with configured %s model: %s",
|
|
125
|
-
provider_name.upper(),
|
|
127
|
+
provider_name.value.upper(),
|
|
126
128
|
model_config.name,
|
|
127
129
|
)
|
|
128
130
|
# Use the Model instance directly (has API key baked in)
|
|
@@ -158,7 +160,7 @@ def create_base_agent(
|
|
|
158
160
|
|
|
159
161
|
agent = Agent(
|
|
160
162
|
model,
|
|
161
|
-
output_type=
|
|
163
|
+
output_type=AgentResponse,
|
|
162
164
|
deps_type=AgentDeps,
|
|
163
165
|
instrument=True,
|
|
164
166
|
history_processors=[history_processor],
|
|
@@ -173,11 +175,6 @@ def create_base_agent(
|
|
|
173
175
|
for tool in additional_tools or []:
|
|
174
176
|
agent.tool_plain(tool)
|
|
175
177
|
|
|
176
|
-
# Register interactive tool conditionally based on deps
|
|
177
|
-
if deps.interactive_mode:
|
|
178
|
-
agent.tool(ask_user)
|
|
179
|
-
logger.debug("📞 Interactive mode enabled - ask_user tool registered")
|
|
180
|
-
|
|
181
178
|
# Register common file management tools (always available)
|
|
182
179
|
agent.tool(write_file)
|
|
183
180
|
agent.tool(append_file)
|
|
@@ -198,7 +195,7 @@ def create_base_agent(
|
|
|
198
195
|
return agent, deps
|
|
199
196
|
|
|
200
197
|
|
|
201
|
-
def _extract_file_toc_content(
|
|
198
|
+
async def _extract_file_toc_content(
|
|
202
199
|
file_path: Path, max_depth: int | None = None, max_chars: int = 500
|
|
203
200
|
) -> str | None:
|
|
204
201
|
"""Extract TOC from a single file with depth and character limits.
|
|
@@ -215,7 +212,8 @@ def _extract_file_toc_content(
|
|
|
215
212
|
return None
|
|
216
213
|
|
|
217
214
|
try:
|
|
218
|
-
|
|
215
|
+
async with aiofiles.open(file_path, encoding="utf-8") as f:
|
|
216
|
+
content = await f.read()
|
|
219
217
|
lines = content.split("\n")
|
|
220
218
|
|
|
221
219
|
# Extract headings
|
|
@@ -261,7 +259,7 @@ def _extract_file_toc_content(
|
|
|
261
259
|
return None
|
|
262
260
|
|
|
263
261
|
|
|
264
|
-
def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
|
|
262
|
+
async def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
|
|
265
263
|
"""Extract TOCs from current and prior agents' files in the pipeline.
|
|
266
264
|
|
|
267
265
|
Shows full TOC of agent's own file and high-level summaries of prior agents'
|
|
@@ -313,22 +311,30 @@ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
|
|
|
313
311
|
for prior_file in config.prior_files:
|
|
314
312
|
file_path = base_path / prior_file
|
|
315
313
|
# Only show # and ## headings from prior files, max 500 chars each
|
|
316
|
-
prior_toc = _extract_file_toc_content(
|
|
314
|
+
prior_toc = await _extract_file_toc_content(
|
|
315
|
+
file_path, max_depth=2, max_chars=500
|
|
316
|
+
)
|
|
317
317
|
if prior_toc:
|
|
318
318
|
# Add section with XML tags
|
|
319
319
|
toc_sections.append(
|
|
320
|
-
f'<TABLE_OF_CONTENTS file_name="{prior_file}">\n
|
|
320
|
+
f'<TABLE_OF_CONTENTS file_name="{prior_file}">\n'
|
|
321
|
+
f"{prior_toc}\n"
|
|
322
|
+
f"</TABLE_OF_CONTENTS>"
|
|
321
323
|
)
|
|
322
324
|
|
|
323
325
|
# Extract TOC from own file (full detail)
|
|
324
326
|
if config.own_file:
|
|
325
327
|
own_path = base_path / config.own_file
|
|
326
|
-
own_toc = _extract_file_toc_content(
|
|
328
|
+
own_toc = await _extract_file_toc_content(
|
|
329
|
+
own_path, max_depth=None, max_chars=2000
|
|
330
|
+
)
|
|
327
331
|
if own_toc:
|
|
328
332
|
# Put own file TOC at the beginning with XML tags
|
|
329
333
|
toc_sections.insert(
|
|
330
334
|
0,
|
|
331
|
-
f'<TABLE_OF_CONTENTS file_name="{config.own_file}">\n
|
|
335
|
+
f'<TABLE_OF_CONTENTS file_name="{config.own_file}">\n'
|
|
336
|
+
f"{own_toc}\n"
|
|
337
|
+
f"</TABLE_OF_CONTENTS>",
|
|
332
338
|
)
|
|
333
339
|
|
|
334
340
|
# Combine all sections
|
|
@@ -384,23 +390,48 @@ def get_agent_existing_files(agent_mode: AgentType | None = None) -> list[str]:
|
|
|
384
390
|
relative_path = file_path.relative_to(base_path)
|
|
385
391
|
existing_files.append(str(relative_path))
|
|
386
392
|
else:
|
|
387
|
-
# For other agents, check
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
#
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
#
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
393
|
+
# For other agents, check files/directories they have access to
|
|
394
|
+
allowed_paths_raw = AGENT_DIRECTORIES[agent_mode]
|
|
395
|
+
|
|
396
|
+
# Convert single Path/string to list of Paths for uniform handling
|
|
397
|
+
if isinstance(allowed_paths_raw, str):
|
|
398
|
+
# Special case: "*" means export agent (shouldn't reach here but handle it)
|
|
399
|
+
allowed_paths = (
|
|
400
|
+
[Path(allowed_paths_raw)] if allowed_paths_raw != "*" else []
|
|
401
|
+
)
|
|
402
|
+
elif isinstance(allowed_paths_raw, Path):
|
|
403
|
+
allowed_paths = [allowed_paths_raw]
|
|
404
|
+
else:
|
|
405
|
+
# Already a list
|
|
406
|
+
allowed_paths = allowed_paths_raw
|
|
407
|
+
|
|
408
|
+
# Check each allowed path
|
|
409
|
+
for allowed_path in allowed_paths:
|
|
410
|
+
allowed_str = str(allowed_path)
|
|
411
|
+
|
|
412
|
+
# Check if it's a directory (no .md suffix)
|
|
413
|
+
if not allowed_path.suffix or not allowed_str.endswith(".md"):
|
|
414
|
+
# It's a directory - list all files within it
|
|
415
|
+
dir_path = base_path / allowed_str
|
|
416
|
+
if dir_path.exists() and dir_path.is_dir():
|
|
417
|
+
for file_path in dir_path.rglob("*"):
|
|
418
|
+
if file_path.is_file():
|
|
419
|
+
relative_path = file_path.relative_to(base_path)
|
|
420
|
+
existing_files.append(str(relative_path))
|
|
421
|
+
else:
|
|
422
|
+
# It's a file - check if it exists
|
|
423
|
+
file_path = base_path / allowed_str
|
|
424
|
+
if file_path.exists():
|
|
425
|
+
existing_files.append(allowed_str)
|
|
426
|
+
|
|
427
|
+
# Also check for associated directory (e.g., research/ for research.md)
|
|
428
|
+
base_name = allowed_str.replace(".md", "")
|
|
429
|
+
dir_path = base_path / base_name
|
|
430
|
+
if dir_path.exists() and dir_path.is_dir():
|
|
431
|
+
for file_path in dir_path.rglob("*"):
|
|
432
|
+
if file_path.is_file():
|
|
433
|
+
relative_path = file_path.relative_to(base_path)
|
|
434
|
+
existing_files.append(str(relative_path))
|
|
404
435
|
|
|
405
436
|
return existing_files
|
|
406
437
|
|
|
@@ -470,7 +501,8 @@ async def add_system_prompt_message(
|
|
|
470
501
|
message_history = message_history or []
|
|
471
502
|
|
|
472
503
|
# Create a minimal RunContext to call the system prompt function
|
|
473
|
-
# We'll pass None for model and usage since they're not used
|
|
504
|
+
# We'll pass None for model and usage since they're not used
|
|
505
|
+
# by our system prompt functions
|
|
474
506
|
context = type(
|
|
475
507
|
"RunContext", (), {"deps": deps, "retry": 0, "model": None, "usage": None}
|
|
476
508
|
)()
|
|
@@ -494,12 +526,12 @@ async def add_system_prompt_message(
|
|
|
494
526
|
|
|
495
527
|
|
|
496
528
|
async def run_agent(
|
|
497
|
-
agent: Agent[AgentDeps,
|
|
529
|
+
agent: Agent[AgentDeps, AgentResponse],
|
|
498
530
|
prompt: str,
|
|
499
531
|
deps: AgentDeps,
|
|
500
532
|
message_history: list[ModelMessage] | None = None,
|
|
501
533
|
usage_limits: UsageLimits | None = None,
|
|
502
|
-
) -> AgentRunResult[
|
|
534
|
+
) -> AgentRunResult[AgentResponse]:
|
|
503
535
|
# Clear file tracker for new run
|
|
504
536
|
deps.file_tracker.clear()
|
|
505
537
|
logger.debug("🔧 Cleared file tracker for new agent run")
|
|
@@ -514,33 +546,6 @@ async def run_agent(
|
|
|
514
546
|
message_history=message_history,
|
|
515
547
|
)
|
|
516
548
|
|
|
517
|
-
# Apply persistent compaction to prevent cascading token growth across CLI commands
|
|
518
|
-
messages = await apply_persistent_compaction(result.all_messages(), deps)
|
|
519
|
-
while isinstance(result.output, DeferredToolRequests):
|
|
520
|
-
logger.info("got deferred tool requests")
|
|
521
|
-
await deps.queue.join()
|
|
522
|
-
requests = result.output
|
|
523
|
-
done, _ = await asyncio.wait(deps.tasks)
|
|
524
|
-
|
|
525
|
-
task_results = [task.result() for task in done]
|
|
526
|
-
task_results_by_tool_call_id = {
|
|
527
|
-
result.tool_call_id: result.answer for result in task_results
|
|
528
|
-
}
|
|
529
|
-
logger.info("got task results", task_results_by_tool_call_id)
|
|
530
|
-
results = DeferredToolResults()
|
|
531
|
-
for call in requests.calls:
|
|
532
|
-
results.calls[call.tool_call_id] = task_results_by_tool_call_id[
|
|
533
|
-
call.tool_call_id
|
|
534
|
-
]
|
|
535
|
-
result = await agent.run(
|
|
536
|
-
deps=deps,
|
|
537
|
-
usage_limits=usage_limits,
|
|
538
|
-
message_history=messages,
|
|
539
|
-
deferred_tool_results=results,
|
|
540
|
-
)
|
|
541
|
-
# Apply persistent compaction to prevent cascading token growth in multi-turn loops
|
|
542
|
-
messages = await apply_persistent_compaction(result.all_messages(), deps)
|
|
543
|
-
|
|
544
549
|
# Log file operations summary if any files were modified
|
|
545
550
|
if deps.file_tracker.operations:
|
|
546
551
|
summary = deps.file_tracker.format_summary()
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
"""Configuration constants for Shotgun agents."""
|
|
2
2
|
|
|
3
|
+
from enum import StrEnum, auto
|
|
4
|
+
|
|
3
5
|
# Field names
|
|
4
6
|
API_KEY_FIELD = "api_key"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
SUPABASE_JWT_FIELD = "supabase_jwt"
|
|
8
|
+
SHOTGUN_INSTANCE_ID_FIELD = "shotgun_instance_id"
|
|
7
9
|
CONFIG_VERSION_FIELD = "config_version"
|
|
8
10
|
|
|
9
|
-
# Provider names (for consistency with data dict keys)
|
|
10
|
-
OPENAI_PROVIDER = "openai"
|
|
11
|
-
ANTHROPIC_PROVIDER = "anthropic"
|
|
12
|
-
GOOGLE_PROVIDER = "google"
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
class ConfigSection(StrEnum):
|
|
13
|
+
"""Configuration file section names (JSON keys)."""
|
|
14
|
+
|
|
15
|
+
OPENAI = auto()
|
|
16
|
+
ANTHROPIC = auto()
|
|
17
|
+
GOOGLE = auto()
|
|
18
|
+
SHOTGUN = auto()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Backwards compatibility - deprecated
|
|
22
|
+
OPENAI_PROVIDER = ConfigSection.OPENAI.value
|
|
23
|
+
ANTHROPIC_PROVIDER = ConfigSection.ANTHROPIC.value
|
|
24
|
+
GOOGLE_PROVIDER = ConfigSection.GOOGLE.value
|
|
25
|
+
SHOTGUN_PROVIDER = ConfigSection.SHOTGUN.value
|
|
26
|
+
|
|
27
|
+
# Token limits
|
|
28
|
+
MEDIUM_TEXT_8K_TOKENS = 8192 # Default max_tokens for web search requests
|