emdash-core 0.1.7__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.
- emdash_core/__init__.py +3 -0
- emdash_core/agent/__init__.py +37 -0
- emdash_core/agent/agents.py +225 -0
- emdash_core/agent/code_reviewer.py +476 -0
- emdash_core/agent/compaction.py +143 -0
- emdash_core/agent/context_manager.py +140 -0
- emdash_core/agent/events.py +338 -0
- emdash_core/agent/handlers.py +224 -0
- emdash_core/agent/inprocess_subagent.py +377 -0
- emdash_core/agent/mcp/__init__.py +50 -0
- emdash_core/agent/mcp/client.py +346 -0
- emdash_core/agent/mcp/config.py +302 -0
- emdash_core/agent/mcp/manager.py +496 -0
- emdash_core/agent/mcp/tool_factory.py +213 -0
- emdash_core/agent/prompts/__init__.py +38 -0
- emdash_core/agent/prompts/main_agent.py +104 -0
- emdash_core/agent/prompts/subagents.py +131 -0
- emdash_core/agent/prompts/workflow.py +136 -0
- emdash_core/agent/providers/__init__.py +34 -0
- emdash_core/agent/providers/base.py +143 -0
- emdash_core/agent/providers/factory.py +80 -0
- emdash_core/agent/providers/models.py +220 -0
- emdash_core/agent/providers/openai_provider.py +463 -0
- emdash_core/agent/providers/transformers_provider.py +217 -0
- emdash_core/agent/research/__init__.py +81 -0
- emdash_core/agent/research/agent.py +143 -0
- emdash_core/agent/research/controller.py +254 -0
- emdash_core/agent/research/critic.py +428 -0
- emdash_core/agent/research/macros.py +469 -0
- emdash_core/agent/research/planner.py +449 -0
- emdash_core/agent/research/researcher.py +436 -0
- emdash_core/agent/research/state.py +523 -0
- emdash_core/agent/research/synthesizer.py +594 -0
- emdash_core/agent/reviewer_profile.py +475 -0
- emdash_core/agent/rules.py +123 -0
- emdash_core/agent/runner.py +601 -0
- emdash_core/agent/session.py +262 -0
- emdash_core/agent/spec_schema.py +66 -0
- emdash_core/agent/specification.py +479 -0
- emdash_core/agent/subagent.py +397 -0
- emdash_core/agent/subagent_prompts.py +13 -0
- emdash_core/agent/toolkit.py +482 -0
- emdash_core/agent/toolkits/__init__.py +64 -0
- emdash_core/agent/toolkits/base.py +96 -0
- emdash_core/agent/toolkits/explore.py +47 -0
- emdash_core/agent/toolkits/plan.py +55 -0
- emdash_core/agent/tools/__init__.py +141 -0
- emdash_core/agent/tools/analytics.py +436 -0
- emdash_core/agent/tools/base.py +131 -0
- emdash_core/agent/tools/coding.py +484 -0
- emdash_core/agent/tools/github_mcp.py +592 -0
- emdash_core/agent/tools/history.py +13 -0
- emdash_core/agent/tools/modes.py +153 -0
- emdash_core/agent/tools/plan.py +206 -0
- emdash_core/agent/tools/plan_write.py +135 -0
- emdash_core/agent/tools/search.py +412 -0
- emdash_core/agent/tools/spec.py +341 -0
- emdash_core/agent/tools/task.py +262 -0
- emdash_core/agent/tools/task_output.py +204 -0
- emdash_core/agent/tools/tasks.py +454 -0
- emdash_core/agent/tools/traversal.py +588 -0
- emdash_core/agent/tools/web.py +179 -0
- emdash_core/analytics/__init__.py +5 -0
- emdash_core/analytics/engine.py +1286 -0
- emdash_core/api/__init__.py +5 -0
- emdash_core/api/agent.py +308 -0
- emdash_core/api/agents.py +154 -0
- emdash_core/api/analyze.py +264 -0
- emdash_core/api/auth.py +173 -0
- emdash_core/api/context.py +77 -0
- emdash_core/api/db.py +121 -0
- emdash_core/api/embed.py +131 -0
- emdash_core/api/feature.py +143 -0
- emdash_core/api/health.py +93 -0
- emdash_core/api/index.py +162 -0
- emdash_core/api/plan.py +110 -0
- emdash_core/api/projectmd.py +210 -0
- emdash_core/api/query.py +320 -0
- emdash_core/api/research.py +122 -0
- emdash_core/api/review.py +161 -0
- emdash_core/api/router.py +76 -0
- emdash_core/api/rules.py +116 -0
- emdash_core/api/search.py +119 -0
- emdash_core/api/spec.py +99 -0
- emdash_core/api/swarm.py +223 -0
- emdash_core/api/tasks.py +109 -0
- emdash_core/api/team.py +120 -0
- emdash_core/auth/__init__.py +17 -0
- emdash_core/auth/github.py +389 -0
- emdash_core/config.py +74 -0
- emdash_core/context/__init__.py +52 -0
- emdash_core/context/models.py +50 -0
- emdash_core/context/providers/__init__.py +11 -0
- emdash_core/context/providers/base.py +74 -0
- emdash_core/context/providers/explored_areas.py +183 -0
- emdash_core/context/providers/touched_areas.py +360 -0
- emdash_core/context/registry.py +73 -0
- emdash_core/context/reranker.py +199 -0
- emdash_core/context/service.py +260 -0
- emdash_core/context/session.py +352 -0
- emdash_core/core/__init__.py +104 -0
- emdash_core/core/config.py +454 -0
- emdash_core/core/exceptions.py +55 -0
- emdash_core/core/models.py +265 -0
- emdash_core/core/review_config.py +57 -0
- emdash_core/db/__init__.py +67 -0
- emdash_core/db/auth.py +134 -0
- emdash_core/db/models.py +91 -0
- emdash_core/db/provider.py +222 -0
- emdash_core/db/providers/__init__.py +5 -0
- emdash_core/db/providers/supabase.py +452 -0
- emdash_core/embeddings/__init__.py +24 -0
- emdash_core/embeddings/indexer.py +534 -0
- emdash_core/embeddings/models.py +192 -0
- emdash_core/embeddings/providers/__init__.py +7 -0
- emdash_core/embeddings/providers/base.py +112 -0
- emdash_core/embeddings/providers/fireworks.py +141 -0
- emdash_core/embeddings/providers/openai.py +104 -0
- emdash_core/embeddings/registry.py +146 -0
- emdash_core/embeddings/service.py +215 -0
- emdash_core/graph/__init__.py +26 -0
- emdash_core/graph/builder.py +134 -0
- emdash_core/graph/connection.py +692 -0
- emdash_core/graph/schema.py +416 -0
- emdash_core/graph/writer.py +667 -0
- emdash_core/ingestion/__init__.py +7 -0
- emdash_core/ingestion/change_detector.py +150 -0
- emdash_core/ingestion/git/__init__.py +5 -0
- emdash_core/ingestion/git/commit_analyzer.py +196 -0
- emdash_core/ingestion/github/__init__.py +6 -0
- emdash_core/ingestion/github/pr_fetcher.py +296 -0
- emdash_core/ingestion/github/task_extractor.py +100 -0
- emdash_core/ingestion/orchestrator.py +540 -0
- emdash_core/ingestion/parsers/__init__.py +10 -0
- emdash_core/ingestion/parsers/base_parser.py +66 -0
- emdash_core/ingestion/parsers/call_graph_builder.py +121 -0
- emdash_core/ingestion/parsers/class_extractor.py +154 -0
- emdash_core/ingestion/parsers/function_extractor.py +202 -0
- emdash_core/ingestion/parsers/import_analyzer.py +119 -0
- emdash_core/ingestion/parsers/python_parser.py +123 -0
- emdash_core/ingestion/parsers/registry.py +72 -0
- emdash_core/ingestion/parsers/ts_ast_parser.js +313 -0
- emdash_core/ingestion/parsers/typescript_parser.py +278 -0
- emdash_core/ingestion/repository.py +346 -0
- emdash_core/models/__init__.py +38 -0
- emdash_core/models/agent.py +68 -0
- emdash_core/models/index.py +77 -0
- emdash_core/models/query.py +113 -0
- emdash_core/planning/__init__.py +7 -0
- emdash_core/planning/agent_api.py +413 -0
- emdash_core/planning/context_builder.py +265 -0
- emdash_core/planning/feature_context.py +232 -0
- emdash_core/planning/feature_expander.py +646 -0
- emdash_core/planning/llm_explainer.py +198 -0
- emdash_core/planning/similarity.py +509 -0
- emdash_core/planning/team_focus.py +821 -0
- emdash_core/server.py +153 -0
- emdash_core/sse/__init__.py +5 -0
- emdash_core/sse/stream.py +196 -0
- emdash_core/swarm/__init__.py +17 -0
- emdash_core/swarm/merge_agent.py +383 -0
- emdash_core/swarm/session_manager.py +274 -0
- emdash_core/swarm/swarm_runner.py +226 -0
- emdash_core/swarm/task_definition.py +137 -0
- emdash_core/swarm/worker_spawner.py +319 -0
- emdash_core/swarm/worktree_manager.py +278 -0
- emdash_core/templates/__init__.py +10 -0
- emdash_core/templates/defaults/agent-builder.md.template +82 -0
- emdash_core/templates/defaults/focus.md.template +115 -0
- emdash_core/templates/defaults/pr-review-enhanced.md.template +309 -0
- emdash_core/templates/defaults/pr-review.md.template +80 -0
- emdash_core/templates/defaults/project.md.template +85 -0
- emdash_core/templates/defaults/research_critic.md.template +112 -0
- emdash_core/templates/defaults/research_planner.md.template +85 -0
- emdash_core/templates/defaults/research_synthesizer.md.template +128 -0
- emdash_core/templates/defaults/reviewer.md.template +81 -0
- emdash_core/templates/defaults/spec.md.template +41 -0
- emdash_core/templates/defaults/tasks.md.template +78 -0
- emdash_core/templates/loader.py +296 -0
- emdash_core/utils/__init__.py +45 -0
- emdash_core/utils/git.py +84 -0
- emdash_core/utils/image.py +502 -0
- emdash_core/utils/logger.py +51 -0
- emdash_core-0.1.7.dist-info/METADATA +35 -0
- emdash_core-0.1.7.dist-info/RECORD +187 -0
- emdash_core-0.1.7.dist-info/WHEEL +4 -0
- emdash_core-0.1.7.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""LLM-based feature explanation using AST graph context."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from ..core.config import get_config
|
|
6
|
+
from .feature_context import FeatureContext
|
|
7
|
+
from ..utils.logger import log
|
|
8
|
+
from ..agent.providers import get_provider
|
|
9
|
+
from ..agent.providers.factory import DEFAULT_MODEL
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LLMExplainer:
|
|
13
|
+
"""Uses LLM to explain a feature graph."""
|
|
14
|
+
|
|
15
|
+
SYSTEM_PROMPTS = {
|
|
16
|
+
"developer": """You are a senior developer explaining code to another developer.
|
|
17
|
+
Focus on:
|
|
18
|
+
- Implementation details and patterns used
|
|
19
|
+
- How components interact with each other
|
|
20
|
+
- Key functions and their responsibilities
|
|
21
|
+
- Important design decisions
|
|
22
|
+
|
|
23
|
+
Be technical but clear. Use code references when helpful.""",
|
|
24
|
+
|
|
25
|
+
"architect": """You are a software architect explaining system design.
|
|
26
|
+
Focus on:
|
|
27
|
+
- High-level architecture and design patterns
|
|
28
|
+
- Module boundaries and dependencies
|
|
29
|
+
- Data flow between components
|
|
30
|
+
- Extensibility and maintainability considerations
|
|
31
|
+
|
|
32
|
+
Think about the big picture and system organization.""",
|
|
33
|
+
|
|
34
|
+
"onboarding": """You are helping a new developer understand the codebase.
|
|
35
|
+
Focus on:
|
|
36
|
+
- What this code does in simple terms
|
|
37
|
+
- Why it's structured this way
|
|
38
|
+
- Key concepts a newcomer should understand
|
|
39
|
+
- How to get started working with this code
|
|
40
|
+
|
|
41
|
+
Use analogies and clear explanations. Avoid jargon where possible.""",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
def __init__(self, model: str = DEFAULT_MODEL):
|
|
45
|
+
"""Initialize LLM explainer.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
model: LLM model to use (claude-* for Anthropic, gpt-* for OpenAI)
|
|
49
|
+
"""
|
|
50
|
+
self.model = model
|
|
51
|
+
self._provider = None
|
|
52
|
+
self._available = None
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def is_available(self) -> bool:
|
|
56
|
+
"""Check if LLM is available."""
|
|
57
|
+
if self._available is None:
|
|
58
|
+
try:
|
|
59
|
+
# Try to create provider to check availability
|
|
60
|
+
self._provider = get_provider(self.model)
|
|
61
|
+
self._available = True
|
|
62
|
+
except ValueError as e:
|
|
63
|
+
log.warning(f"LLM provider not available: {e}")
|
|
64
|
+
self._available = False
|
|
65
|
+
return self._available
|
|
66
|
+
|
|
67
|
+
def explain_feature(
|
|
68
|
+
self,
|
|
69
|
+
context: FeatureContext,
|
|
70
|
+
style: str = "developer",
|
|
71
|
+
model: Optional[str] = None,
|
|
72
|
+
max_tokens: int = 2000,
|
|
73
|
+
) -> str:
|
|
74
|
+
"""Generate LLM explanation of the feature.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
context: The feature context with AST graph
|
|
78
|
+
style: Explanation style - "developer", "architect", or "onboarding"
|
|
79
|
+
model: LLM model to use (defaults to instance model)
|
|
80
|
+
max_tokens: Maximum tokens in response (used as hint)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
LLM-generated explanation
|
|
84
|
+
"""
|
|
85
|
+
if not self.is_available:
|
|
86
|
+
return "Error: LLM API key not configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable."
|
|
87
|
+
|
|
88
|
+
# Use provided model or default
|
|
89
|
+
use_model = model or self.model
|
|
90
|
+
if use_model != self.model:
|
|
91
|
+
provider = get_provider(use_model)
|
|
92
|
+
else:
|
|
93
|
+
provider = self._provider
|
|
94
|
+
|
|
95
|
+
prompt = self._build_prompt(context)
|
|
96
|
+
system_prompt = self.SYSTEM_PROMPTS.get(style, self.SYSTEM_PROMPTS["developer"])
|
|
97
|
+
|
|
98
|
+
log.info(f"Generating {style} explanation for: {context.query}")
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
response = provider.chat(
|
|
102
|
+
messages=[{"role": "user", "content": prompt}],
|
|
103
|
+
system=system_prompt,
|
|
104
|
+
)
|
|
105
|
+
return response.content or ""
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
log.error(f"LLM explanation failed: {e}")
|
|
109
|
+
return f"Error generating explanation: {e}"
|
|
110
|
+
|
|
111
|
+
def _build_prompt(self, context: FeatureContext) -> str:
|
|
112
|
+
"""Build prompt from feature context."""
|
|
113
|
+
graph = context.feature_graph
|
|
114
|
+
|
|
115
|
+
sections = []
|
|
116
|
+
|
|
117
|
+
# Query
|
|
118
|
+
sections.append(f"# Feature Query: {context.query}")
|
|
119
|
+
sections.append("")
|
|
120
|
+
|
|
121
|
+
# Root node
|
|
122
|
+
root = context.root_node
|
|
123
|
+
sections.append("## Starting Point")
|
|
124
|
+
sections.append(f"- **Type**: {root.get('type', 'Unknown')}")
|
|
125
|
+
sections.append(f"- **Name**: {root.get('name', 'Unknown')}")
|
|
126
|
+
sections.append(f"- **File**: {root.get('file_path', 'N/A')}")
|
|
127
|
+
if root.get('docstring'):
|
|
128
|
+
docstring = root['docstring'][:300]
|
|
129
|
+
sections.append(f"- **Description**: {docstring}")
|
|
130
|
+
sections.append("")
|
|
131
|
+
|
|
132
|
+
# Call graph
|
|
133
|
+
if graph.call_graph:
|
|
134
|
+
sections.append("## Function Call Graph")
|
|
135
|
+
for call in graph.call_graph[:15]:
|
|
136
|
+
sections.append(f"- `{call['caller']}` calls `{call['callee']}`")
|
|
137
|
+
if len(graph.call_graph) > 15:
|
|
138
|
+
sections.append(f"- ... and {len(graph.call_graph) - 15} more calls")
|
|
139
|
+
sections.append("")
|
|
140
|
+
|
|
141
|
+
# Classes
|
|
142
|
+
if graph.classes:
|
|
143
|
+
sections.append("## Classes Involved")
|
|
144
|
+
for cls in graph.classes[:10]:
|
|
145
|
+
name = cls.get('name', 'Unknown')
|
|
146
|
+
doc = cls.get('docstring') or 'No description'
|
|
147
|
+
sections.append(f"- **{name}**: {doc[:100]}")
|
|
148
|
+
if len(graph.classes) > 10:
|
|
149
|
+
sections.append(f"- ... and {len(graph.classes) - 10} more classes")
|
|
150
|
+
sections.append("")
|
|
151
|
+
|
|
152
|
+
# Functions
|
|
153
|
+
if graph.functions:
|
|
154
|
+
sections.append("## Key Functions")
|
|
155
|
+
for func in graph.functions[:12]:
|
|
156
|
+
name = func.get('name', 'Unknown')
|
|
157
|
+
doc = func.get('docstring') or 'No description'
|
|
158
|
+
sections.append(f"- **{name}**: {doc[:80]}")
|
|
159
|
+
if len(graph.functions) > 12:
|
|
160
|
+
sections.append(f"- ... and {len(graph.functions) - 12} more functions")
|
|
161
|
+
sections.append("")
|
|
162
|
+
|
|
163
|
+
# Inheritance
|
|
164
|
+
if graph.inheritance:
|
|
165
|
+
sections.append("## Class Inheritance")
|
|
166
|
+
for inh in graph.inheritance[:8]:
|
|
167
|
+
sections.append(f"- `{inh['child']}` extends `{inh['parent']}`")
|
|
168
|
+
sections.append("")
|
|
169
|
+
|
|
170
|
+
# Files
|
|
171
|
+
if graph.files:
|
|
172
|
+
sections.append("## Files")
|
|
173
|
+
for f in graph.files[:8]:
|
|
174
|
+
path = f.get('path', f.get('name', 'Unknown'))
|
|
175
|
+
sections.append(f"- `{path}`")
|
|
176
|
+
if len(graph.files) > 8:
|
|
177
|
+
sections.append(f"- ... and {len(graph.files) - 8} more files")
|
|
178
|
+
sections.append("")
|
|
179
|
+
|
|
180
|
+
# Related PRs
|
|
181
|
+
if context.related_prs:
|
|
182
|
+
sections.append("## Related Pull Requests")
|
|
183
|
+
for pr in context.related_prs[:5]:
|
|
184
|
+
sections.append(f"- PR #{pr['number']}: {pr.get('title', 'N/A')}")
|
|
185
|
+
sections.append("")
|
|
186
|
+
|
|
187
|
+
# Authors
|
|
188
|
+
if context.authors:
|
|
189
|
+
sections.append("## Domain Experts")
|
|
190
|
+
for author in context.authors[:5]:
|
|
191
|
+
sections.append(f"- {author['name']} ({author['commit_count']} commits)")
|
|
192
|
+
sections.append("")
|
|
193
|
+
|
|
194
|
+
# Final instruction
|
|
195
|
+
sections.append("---")
|
|
196
|
+
sections.append("Based on the AST graph above, explain how this feature works, its key components, and how they interact.")
|
|
197
|
+
|
|
198
|
+
return "\n".join(sections)
|