shotgun-sh 0.1.0.dev14__tar.gz → 0.1.0.dev16__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.
Potentially problematic release.
This version of shotgun-sh might be problematic. Click here for more details.
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/PKG-INFO +1 -1
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/pyproject.toml +1 -1
- shotgun_sh-0.1.0.dev16/src/shotgun/agents/agent_manager.py +439 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/models.py +20 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/artifact_management.py +2 -3
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/research/sdk_comparison.yaml +73 -73
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +10 -1
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/plan.j2 +9 -12
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/research.j2 +6 -3
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/specify.j2 +8 -9
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/state/artifact_templates_available.j2 +3 -1
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/state/existing_artifacts_available.j2 +2 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/tasks.j2 +1 -1
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +2 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +4 -2
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/app.py +9 -1
- shotgun_sh-0.1.0.dev16/src/shotgun/tui/commands/__init__.py +73 -0
- shotgun_sh-0.1.0.dev16/src/shotgun/tui/screens/chat.py +680 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/screens/chat.tcss +11 -0
- shotgun_sh-0.1.0.dev16/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
- shotgun_sh-0.1.0.dev16/src/shotgun/tui/screens/chat_screen/command_providers.py +197 -0
- shotgun_sh-0.1.0.dev16/src/shotgun/tui/screens/chat_screen/history.py +160 -0
- shotgun_sh-0.1.0.dev14/src/shotgun/agents/agent_manager.py +0 -209
- shotgun_sh-0.1.0.dev14/src/shotgun/tui/screens/chat.py +0 -460
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/.gitignore +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/LICENSE +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/README.md +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/hatch_build.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/artifact_state.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/common.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/config/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/config/constants.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/config/manager.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/config/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/config/provider.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/compaction.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/constants.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/context_extraction.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/history_building.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/history_processors.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/message_utils.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/token_counting.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/history/token_estimation.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/plan.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/research.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/specify.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tasks.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/file_management.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/user_interaction.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/web_search/openai.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/web_search/utils.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/exceptions.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/manager.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/service.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/loader.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/plan/delivery_and_release_plan.yaml +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/research/market_research.yaml +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/specify/prd.yaml +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/templates/specify/product_spec.yaml +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/artifacts/utils.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/build_constants.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/codebase/commands.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/config.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/plan.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/research.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/specify.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/tasks.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/update.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/cli/utils.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/change_detector.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/code_retrieval.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/ingestor.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/language_config.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/manager.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/nl_query.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/core/parser_loader.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/codebase/service.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/logging_config.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/main.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/posthog_telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/partials/artifact_system.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/history/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/history/summarization.j2 +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/prompts/loader.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/py.typed +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/artifact_models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/artifacts.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/codebase.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/exceptions.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/models.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sdk/services.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/sentry_telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/components/prompt_input.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/components/spinner.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/components/splash.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/components/vertical_tail.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/screens/directory_setup.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/screens/provider_config.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/screens/splash.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/tui/styles.tcss +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/utils/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/utils/env_utils.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/utils/file_system_utils.py +0 -0
- {shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/utils/update_checker.py +0 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
"""Agent manager for coordinating multiple AI agents with shared message history."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import AsyncIterable
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Any, cast
|
|
8
|
+
|
|
9
|
+
from pydantic_ai import (
|
|
10
|
+
Agent,
|
|
11
|
+
DeferredToolRequests,
|
|
12
|
+
DeferredToolResults,
|
|
13
|
+
RunContext,
|
|
14
|
+
UsageLimits,
|
|
15
|
+
)
|
|
16
|
+
from pydantic_ai.agent import AgentRunResult
|
|
17
|
+
from pydantic_ai.messages import (
|
|
18
|
+
AgentStreamEvent,
|
|
19
|
+
FinalResultEvent,
|
|
20
|
+
ModelMessage,
|
|
21
|
+
ModelRequest,
|
|
22
|
+
ModelResponse,
|
|
23
|
+
ModelResponsePart,
|
|
24
|
+
PartDeltaEvent,
|
|
25
|
+
PartStartEvent,
|
|
26
|
+
ToolCallPartDelta,
|
|
27
|
+
)
|
|
28
|
+
from textual.message import Message
|
|
29
|
+
from textual.widget import Widget
|
|
30
|
+
|
|
31
|
+
from .history.compaction import apply_persistent_compaction
|
|
32
|
+
from .models import AgentDeps, AgentRuntimeOptions, FileOperation
|
|
33
|
+
from .plan import create_plan_agent
|
|
34
|
+
from .research import create_research_agent
|
|
35
|
+
from .specify import create_specify_agent
|
|
36
|
+
from .tasks import create_tasks_agent
|
|
37
|
+
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AgentType(Enum):
|
|
42
|
+
"""Enumeration for available agent types (for Python < 3.11)."""
|
|
43
|
+
|
|
44
|
+
RESEARCH = "research"
|
|
45
|
+
PLAN = "plan"
|
|
46
|
+
TASKS = "tasks"
|
|
47
|
+
SPECIFY = "specify"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MessageHistoryUpdated(Message):
|
|
51
|
+
"""Event posted when the message history is updated."""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
messages: list[ModelMessage],
|
|
56
|
+
agent_type: AgentType,
|
|
57
|
+
file_operations: list[FileOperation] | None = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""Initialize the message history updated event.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
messages: The updated message history.
|
|
63
|
+
agent_type: The type of agent that triggered the update.
|
|
64
|
+
file_operations: List of file operations from this run.
|
|
65
|
+
"""
|
|
66
|
+
super().__init__()
|
|
67
|
+
self.messages = messages
|
|
68
|
+
self.agent_type = agent_type
|
|
69
|
+
self.file_operations = file_operations or []
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class PartialResponseMessage(Message):
|
|
73
|
+
"""Event posted when a partial response is received."""
|
|
74
|
+
|
|
75
|
+
def __init__(self, message: ModelResponse | None, is_last: bool) -> None:
|
|
76
|
+
"""Initialize the partial response message."""
|
|
77
|
+
super().__init__()
|
|
78
|
+
self.message = message
|
|
79
|
+
self.is_last = is_last
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(slots=True)
|
|
83
|
+
class _PartialStreamState:
|
|
84
|
+
"""Tracks partial response parts while streaming a single agent run."""
|
|
85
|
+
|
|
86
|
+
parts: list[ModelResponsePart | ToolCallPartDelta] = field(default_factory=list)
|
|
87
|
+
latest_partial: ModelResponse | None = None
|
|
88
|
+
final_sent: bool = False
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class AgentManager(Widget):
|
|
92
|
+
"""Manages multiple agents with shared message history."""
|
|
93
|
+
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
deps: AgentDeps | None = None,
|
|
97
|
+
initial_type: AgentType = AgentType.RESEARCH,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Initialize the agent manager.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
deps: Optional agent dependencies. If not provided, defaults to interactive mode.
|
|
103
|
+
"""
|
|
104
|
+
super().__init__()
|
|
105
|
+
self.display = False
|
|
106
|
+
|
|
107
|
+
# Use provided deps or create default with interactive mode
|
|
108
|
+
self.deps = deps
|
|
109
|
+
|
|
110
|
+
if self.deps is None:
|
|
111
|
+
raise ValueError("AgentDeps must be provided to AgentManager")
|
|
112
|
+
|
|
113
|
+
# Create AgentRuntimeOptions from deps for agent creation
|
|
114
|
+
agent_runtime_options = AgentRuntimeOptions(
|
|
115
|
+
interactive_mode=self.deps.interactive_mode,
|
|
116
|
+
working_directory=self.deps.working_directory,
|
|
117
|
+
max_iterations=self.deps.max_iterations,
|
|
118
|
+
queue=self.deps.queue,
|
|
119
|
+
tasks=self.deps.tasks,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Initialize all agents and store their specific deps
|
|
123
|
+
self.research_agent, self.research_deps = create_research_agent(
|
|
124
|
+
agent_runtime_options=agent_runtime_options
|
|
125
|
+
)
|
|
126
|
+
self.plan_agent, self.plan_deps = create_plan_agent(
|
|
127
|
+
agent_runtime_options=agent_runtime_options
|
|
128
|
+
)
|
|
129
|
+
self.tasks_agent, self.tasks_deps = create_tasks_agent(
|
|
130
|
+
agent_runtime_options=agent_runtime_options
|
|
131
|
+
)
|
|
132
|
+
self.specify_agent, self.specify_deps = create_specify_agent(
|
|
133
|
+
agent_runtime_options=agent_runtime_options
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Track current active agent
|
|
137
|
+
self._current_agent_type: AgentType = initial_type
|
|
138
|
+
|
|
139
|
+
# Maintain shared message history
|
|
140
|
+
self.ui_message_history: list[ModelMessage] = []
|
|
141
|
+
self.message_history: list[ModelMessage] = []
|
|
142
|
+
self.recently_change_files: list[FileOperation] = []
|
|
143
|
+
self._stream_state: _PartialStreamState | None = None
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def current_agent(self) -> Agent[AgentDeps, str | DeferredToolRequests]:
|
|
147
|
+
"""Get the currently active agent.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
The currently selected agent instance.
|
|
151
|
+
"""
|
|
152
|
+
return self._get_agent(self._current_agent_type)
|
|
153
|
+
|
|
154
|
+
def _get_agent(
|
|
155
|
+
self, agent_type: AgentType
|
|
156
|
+
) -> Agent[AgentDeps, str | DeferredToolRequests]:
|
|
157
|
+
"""Get agent by type.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
agent_type: The type of agent to retrieve.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
The requested agent instance.
|
|
164
|
+
"""
|
|
165
|
+
agent_map = {
|
|
166
|
+
AgentType.RESEARCH: self.research_agent,
|
|
167
|
+
AgentType.PLAN: self.plan_agent,
|
|
168
|
+
AgentType.TASKS: self.tasks_agent,
|
|
169
|
+
AgentType.SPECIFY: self.specify_agent,
|
|
170
|
+
}
|
|
171
|
+
return agent_map[agent_type]
|
|
172
|
+
|
|
173
|
+
def _get_agent_deps(self, agent_type: AgentType) -> AgentDeps:
|
|
174
|
+
"""Get agent-specific deps by type.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
agent_type: The type of agent to retrieve deps for.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
The agent-specific dependencies.
|
|
181
|
+
"""
|
|
182
|
+
deps_map = {
|
|
183
|
+
AgentType.RESEARCH: self.research_deps,
|
|
184
|
+
AgentType.PLAN: self.plan_deps,
|
|
185
|
+
AgentType.TASKS: self.tasks_deps,
|
|
186
|
+
AgentType.SPECIFY: self.specify_deps,
|
|
187
|
+
}
|
|
188
|
+
return deps_map[agent_type]
|
|
189
|
+
|
|
190
|
+
def _create_merged_deps(self, agent_type: AgentType) -> AgentDeps:
|
|
191
|
+
"""Create merged dependencies combining shared and agent-specific deps.
|
|
192
|
+
|
|
193
|
+
This preserves the agent's system_prompt_fn while using shared runtime state.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
agent_type: The type of agent to create merged deps for.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Merged AgentDeps with agent-specific system_prompt_fn.
|
|
200
|
+
"""
|
|
201
|
+
agent_deps = self._get_agent_deps(agent_type)
|
|
202
|
+
|
|
203
|
+
# Ensure shared deps is not None (should be guaranteed by __init__)
|
|
204
|
+
if self.deps is None:
|
|
205
|
+
raise ValueError("Shared deps is None - this should not happen")
|
|
206
|
+
|
|
207
|
+
# Create new deps with shared runtime state but agent's system_prompt_fn
|
|
208
|
+
# Use a copy of the shared deps and update the system_prompt_fn
|
|
209
|
+
merged_deps = self.deps.model_copy(
|
|
210
|
+
update={"system_prompt_fn": agent_deps.system_prompt_fn}
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
return merged_deps
|
|
214
|
+
|
|
215
|
+
def set_agent(self, agent_type: AgentType) -> None:
|
|
216
|
+
"""Set the current active agent.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
agent_type: The agent type to activate (AgentType enum or string).
|
|
220
|
+
|
|
221
|
+
Raises:
|
|
222
|
+
ValueError: If invalid agent type is provided.
|
|
223
|
+
"""
|
|
224
|
+
try:
|
|
225
|
+
self._current_agent_type = AgentType(agent_type)
|
|
226
|
+
except ValueError:
|
|
227
|
+
raise ValueError(
|
|
228
|
+
f"Invalid agent type: {agent_type}. Must be one of: {', '.join(e.value for e in AgentType)}"
|
|
229
|
+
) from None
|
|
230
|
+
|
|
231
|
+
async def run(
|
|
232
|
+
self,
|
|
233
|
+
prompt: str | None = None,
|
|
234
|
+
*,
|
|
235
|
+
deps: AgentDeps | None = None,
|
|
236
|
+
usage_limits: UsageLimits | None = None,
|
|
237
|
+
deferred_tool_results: DeferredToolResults | None = None,
|
|
238
|
+
**kwargs: Any,
|
|
239
|
+
) -> AgentRunResult[str | DeferredToolRequests]:
|
|
240
|
+
"""Run the current agent with automatic message history management.
|
|
241
|
+
|
|
242
|
+
This method wraps the agent's run method, automatically injecting the
|
|
243
|
+
shared message history and updating it after each run.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
prompt: Optional prompt to send to the agent.
|
|
247
|
+
deps: Optional dependencies override (defaults to manager's deps).
|
|
248
|
+
usage_limits: Optional usage limits for the agent run.
|
|
249
|
+
deferred_tool_results: Optional deferred tool results for continuing a conversation.
|
|
250
|
+
**kwargs: Additional keyword arguments to pass to the agent.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
The agent run result.
|
|
254
|
+
"""
|
|
255
|
+
# Use merged deps (shared state + agent-specific system prompt) if not provided
|
|
256
|
+
if deps is None:
|
|
257
|
+
deps = self._create_merged_deps(self._current_agent_type)
|
|
258
|
+
|
|
259
|
+
# Ensure deps is not None
|
|
260
|
+
if deps is None:
|
|
261
|
+
raise ValueError("AgentDeps must be provided")
|
|
262
|
+
|
|
263
|
+
if prompt:
|
|
264
|
+
self.ui_message_history.append(ModelRequest.user_text_prompt(prompt))
|
|
265
|
+
self._post_messages_updated()
|
|
266
|
+
|
|
267
|
+
# Ensure system prompt is added to message history before running agent
|
|
268
|
+
from pydantic_ai.messages import SystemPromptPart
|
|
269
|
+
|
|
270
|
+
from shotgun.agents.common import add_system_prompt_message
|
|
271
|
+
|
|
272
|
+
# Start with persistent message history
|
|
273
|
+
message_history = self.message_history
|
|
274
|
+
|
|
275
|
+
# Check if the message history already has a system prompt
|
|
276
|
+
has_system_prompt = any(
|
|
277
|
+
hasattr(msg, "parts")
|
|
278
|
+
and any(isinstance(part, SystemPromptPart) for part in msg.parts)
|
|
279
|
+
for msg in message_history
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
# Always ensure we have a system prompt for the agent
|
|
283
|
+
# (compaction may remove it from persistent history, but agent needs it)
|
|
284
|
+
if not has_system_prompt:
|
|
285
|
+
message_history = await add_system_prompt_message(deps, message_history)
|
|
286
|
+
|
|
287
|
+
# Run the agent with streaming support (from origin/main)
|
|
288
|
+
self._stream_state = _PartialStreamState()
|
|
289
|
+
|
|
290
|
+
model_name = ""
|
|
291
|
+
if hasattr(deps, "llm_model") and deps.llm_model is not None:
|
|
292
|
+
model_name = deps.llm_model.name
|
|
293
|
+
is_gpt5 = ( # streaming is likely not supported for gpt5. It varies between keys.
|
|
294
|
+
"gpt-5" in model_name.lower()
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
result: AgentRunResult[
|
|
299
|
+
str | DeferredToolRequests
|
|
300
|
+
] = await self.current_agent.run(
|
|
301
|
+
prompt,
|
|
302
|
+
deps=deps,
|
|
303
|
+
usage_limits=usage_limits,
|
|
304
|
+
message_history=message_history,
|
|
305
|
+
deferred_tool_results=deferred_tool_results,
|
|
306
|
+
event_stream_handler=self._handle_event_stream if not is_gpt5 else None,
|
|
307
|
+
**kwargs,
|
|
308
|
+
)
|
|
309
|
+
finally:
|
|
310
|
+
# If the stream ended unexpectedly without a final result, clear accumulated state.
|
|
311
|
+
if self._stream_state is not None and not self._stream_state.final_sent:
|
|
312
|
+
partial_message = self._build_partial_response(self._stream_state.parts)
|
|
313
|
+
if partial_message is not None:
|
|
314
|
+
self._post_partial_message(partial_message, True)
|
|
315
|
+
self._stream_state = None
|
|
316
|
+
|
|
317
|
+
self.ui_message_history = self.ui_message_history + [
|
|
318
|
+
mes for mes in result.new_messages() if not isinstance(mes, ModelRequest)
|
|
319
|
+
]
|
|
320
|
+
|
|
321
|
+
# Apply compaction to persistent message history to prevent cascading growth
|
|
322
|
+
all_messages = result.all_messages()
|
|
323
|
+
self.message_history = await apply_persistent_compaction(all_messages, deps)
|
|
324
|
+
|
|
325
|
+
# Log file operations summary if any files were modified
|
|
326
|
+
file_operations = deps.file_tracker.operations.copy()
|
|
327
|
+
self.recently_change_files = file_operations
|
|
328
|
+
|
|
329
|
+
self._post_messages_updated(file_operations)
|
|
330
|
+
|
|
331
|
+
return result
|
|
332
|
+
|
|
333
|
+
async def _handle_event_stream(
|
|
334
|
+
self,
|
|
335
|
+
_ctx: RunContext[AgentDeps],
|
|
336
|
+
stream: AsyncIterable[AgentStreamEvent],
|
|
337
|
+
) -> None:
|
|
338
|
+
"""Process streamed events and forward partial updates to the UI."""
|
|
339
|
+
|
|
340
|
+
state = self._stream_state
|
|
341
|
+
if state is None:
|
|
342
|
+
state = self._stream_state = _PartialStreamState()
|
|
343
|
+
|
|
344
|
+
partial_parts = state.parts
|
|
345
|
+
|
|
346
|
+
async for event in stream:
|
|
347
|
+
try:
|
|
348
|
+
if isinstance(event, PartStartEvent):
|
|
349
|
+
index = event.index
|
|
350
|
+
if index < len(partial_parts):
|
|
351
|
+
partial_parts[index] = event.part
|
|
352
|
+
elif index == len(partial_parts):
|
|
353
|
+
partial_parts.append(event.part)
|
|
354
|
+
else:
|
|
355
|
+
logger.warning(
|
|
356
|
+
"Received PartStartEvent with out-of-bounds index",
|
|
357
|
+
extra={"index": index, "current_len": len(partial_parts)},
|
|
358
|
+
)
|
|
359
|
+
partial_parts.append(event.part)
|
|
360
|
+
|
|
361
|
+
partial_message = self._build_partial_response(partial_parts)
|
|
362
|
+
if partial_message is not None:
|
|
363
|
+
state.latest_partial = partial_message
|
|
364
|
+
self._post_partial_message(partial_message, False)
|
|
365
|
+
|
|
366
|
+
elif isinstance(event, PartDeltaEvent):
|
|
367
|
+
index = event.index
|
|
368
|
+
if index >= len(partial_parts):
|
|
369
|
+
logger.warning(
|
|
370
|
+
"Received PartDeltaEvent before corresponding start event",
|
|
371
|
+
extra={"index": index, "current_len": len(partial_parts)},
|
|
372
|
+
)
|
|
373
|
+
continue
|
|
374
|
+
|
|
375
|
+
try:
|
|
376
|
+
updated_part = event.delta.apply(
|
|
377
|
+
cast(ModelResponsePart, partial_parts[index])
|
|
378
|
+
)
|
|
379
|
+
except Exception: # pragma: no cover - defensive logging
|
|
380
|
+
logger.exception(
|
|
381
|
+
"Failed to apply part delta", extra={"event": event}
|
|
382
|
+
)
|
|
383
|
+
continue
|
|
384
|
+
|
|
385
|
+
partial_parts[index] = updated_part
|
|
386
|
+
|
|
387
|
+
partial_message = self._build_partial_response(partial_parts)
|
|
388
|
+
if partial_message is not None:
|
|
389
|
+
state.latest_partial = partial_message
|
|
390
|
+
self._post_partial_message(partial_message, False)
|
|
391
|
+
|
|
392
|
+
elif isinstance(event, FinalResultEvent):
|
|
393
|
+
final_message = (
|
|
394
|
+
state.latest_partial
|
|
395
|
+
or self._build_partial_response(partial_parts)
|
|
396
|
+
)
|
|
397
|
+
self._post_partial_message(final_message, True)
|
|
398
|
+
state.latest_partial = None
|
|
399
|
+
state.final_sent = True
|
|
400
|
+
partial_parts.clear()
|
|
401
|
+
self._stream_state = None
|
|
402
|
+
break
|
|
403
|
+
|
|
404
|
+
# Ignore other AgentStreamEvent variants (e.g. tool call notifications) for partial UI updates.
|
|
405
|
+
|
|
406
|
+
except Exception: # pragma: no cover - defensive logging
|
|
407
|
+
logger.exception(
|
|
408
|
+
"Error while handling agent stream event", extra={"event": event}
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def _build_partial_response(
|
|
412
|
+
self, parts: list[ModelResponsePart | ToolCallPartDelta]
|
|
413
|
+
) -> ModelResponse | None:
|
|
414
|
+
"""Create a `ModelResponse` from the currently streamed parts."""
|
|
415
|
+
|
|
416
|
+
completed_parts = [
|
|
417
|
+
part for part in parts if not isinstance(part, ToolCallPartDelta)
|
|
418
|
+
]
|
|
419
|
+
if not completed_parts:
|
|
420
|
+
return None
|
|
421
|
+
return ModelResponse(parts=list(completed_parts))
|
|
422
|
+
|
|
423
|
+
def _post_partial_message(
|
|
424
|
+
self, message: ModelResponse | None, is_last: bool
|
|
425
|
+
) -> None:
|
|
426
|
+
"""Post a partial message to the UI."""
|
|
427
|
+
self.post_message(PartialResponseMessage(message, is_last))
|
|
428
|
+
|
|
429
|
+
def _post_messages_updated(
|
|
430
|
+
self, file_operations: list[FileOperation] | None = None
|
|
431
|
+
) -> None:
|
|
432
|
+
# Post event to notify listeners of the message history update
|
|
433
|
+
self.post_message(
|
|
434
|
+
MessageHistoryUpdated(
|
|
435
|
+
messages=self.ui_message_history.copy(),
|
|
436
|
+
agent_type=self._current_agent_type,
|
|
437
|
+
file_operations=file_operations,
|
|
438
|
+
)
|
|
439
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Pydantic models for agent dependencies and configuration."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
from asyncio import Future, Queue
|
|
4
5
|
from collections.abc import Callable
|
|
5
6
|
from datetime import datetime
|
|
@@ -187,6 +188,25 @@ class FileOperationTracker(BaseModel):
|
|
|
187
188
|
|
|
188
189
|
return "\n".join(lines)
|
|
189
190
|
|
|
191
|
+
def get_display_path(self) -> str | None:
|
|
192
|
+
"""Get a single file path or common parent directory for display.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Path string to display, or None if no files were modified
|
|
196
|
+
"""
|
|
197
|
+
if not self.operations:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
unique_paths = list({op.file_path for op in self.operations})
|
|
201
|
+
|
|
202
|
+
if len(unique_paths) == 1:
|
|
203
|
+
# Single file - return its path
|
|
204
|
+
return unique_paths[0]
|
|
205
|
+
|
|
206
|
+
# Multiple files - find common parent directory
|
|
207
|
+
common_path = os.path.commonpath(unique_paths)
|
|
208
|
+
return common_path
|
|
209
|
+
|
|
190
210
|
|
|
191
211
|
class AgentDeps(AgentRuntimeOptions):
|
|
192
212
|
"""Dependencies passed to all agents for configuration and runtime behavior."""
|
{shotgun_sh-0.1.0.dev14 → shotgun_sh-0.1.0.dev16}/src/shotgun/agents/tools/artifact_management.py
RENAMED
|
@@ -347,14 +347,13 @@ async def read_artifact_section(
|
|
|
347
347
|
|
|
348
348
|
section = service.get_section(artifact_id, mode, section_number)
|
|
349
349
|
|
|
350
|
-
# Return
|
|
351
|
-
formatted_content = f"# {section.title}\n\n{section.content}"
|
|
350
|
+
# Return section content (already contains title header from file storage)
|
|
352
351
|
logger.debug(
|
|
353
352
|
"📄 Read section %d with %d characters",
|
|
354
353
|
section_number,
|
|
355
354
|
len(section.content),
|
|
356
355
|
)
|
|
357
|
-
return
|
|
356
|
+
return section.content
|
|
358
357
|
|
|
359
358
|
except Exception as e:
|
|
360
359
|
error_msg = (
|