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.
Files changed (187) hide show
  1. emdash_core/__init__.py +3 -0
  2. emdash_core/agent/__init__.py +37 -0
  3. emdash_core/agent/agents.py +225 -0
  4. emdash_core/agent/code_reviewer.py +476 -0
  5. emdash_core/agent/compaction.py +143 -0
  6. emdash_core/agent/context_manager.py +140 -0
  7. emdash_core/agent/events.py +338 -0
  8. emdash_core/agent/handlers.py +224 -0
  9. emdash_core/agent/inprocess_subagent.py +377 -0
  10. emdash_core/agent/mcp/__init__.py +50 -0
  11. emdash_core/agent/mcp/client.py +346 -0
  12. emdash_core/agent/mcp/config.py +302 -0
  13. emdash_core/agent/mcp/manager.py +496 -0
  14. emdash_core/agent/mcp/tool_factory.py +213 -0
  15. emdash_core/agent/prompts/__init__.py +38 -0
  16. emdash_core/agent/prompts/main_agent.py +104 -0
  17. emdash_core/agent/prompts/subagents.py +131 -0
  18. emdash_core/agent/prompts/workflow.py +136 -0
  19. emdash_core/agent/providers/__init__.py +34 -0
  20. emdash_core/agent/providers/base.py +143 -0
  21. emdash_core/agent/providers/factory.py +80 -0
  22. emdash_core/agent/providers/models.py +220 -0
  23. emdash_core/agent/providers/openai_provider.py +463 -0
  24. emdash_core/agent/providers/transformers_provider.py +217 -0
  25. emdash_core/agent/research/__init__.py +81 -0
  26. emdash_core/agent/research/agent.py +143 -0
  27. emdash_core/agent/research/controller.py +254 -0
  28. emdash_core/agent/research/critic.py +428 -0
  29. emdash_core/agent/research/macros.py +469 -0
  30. emdash_core/agent/research/planner.py +449 -0
  31. emdash_core/agent/research/researcher.py +436 -0
  32. emdash_core/agent/research/state.py +523 -0
  33. emdash_core/agent/research/synthesizer.py +594 -0
  34. emdash_core/agent/reviewer_profile.py +475 -0
  35. emdash_core/agent/rules.py +123 -0
  36. emdash_core/agent/runner.py +601 -0
  37. emdash_core/agent/session.py +262 -0
  38. emdash_core/agent/spec_schema.py +66 -0
  39. emdash_core/agent/specification.py +479 -0
  40. emdash_core/agent/subagent.py +397 -0
  41. emdash_core/agent/subagent_prompts.py +13 -0
  42. emdash_core/agent/toolkit.py +482 -0
  43. emdash_core/agent/toolkits/__init__.py +64 -0
  44. emdash_core/agent/toolkits/base.py +96 -0
  45. emdash_core/agent/toolkits/explore.py +47 -0
  46. emdash_core/agent/toolkits/plan.py +55 -0
  47. emdash_core/agent/tools/__init__.py +141 -0
  48. emdash_core/agent/tools/analytics.py +436 -0
  49. emdash_core/agent/tools/base.py +131 -0
  50. emdash_core/agent/tools/coding.py +484 -0
  51. emdash_core/agent/tools/github_mcp.py +592 -0
  52. emdash_core/agent/tools/history.py +13 -0
  53. emdash_core/agent/tools/modes.py +153 -0
  54. emdash_core/agent/tools/plan.py +206 -0
  55. emdash_core/agent/tools/plan_write.py +135 -0
  56. emdash_core/agent/tools/search.py +412 -0
  57. emdash_core/agent/tools/spec.py +341 -0
  58. emdash_core/agent/tools/task.py +262 -0
  59. emdash_core/agent/tools/task_output.py +204 -0
  60. emdash_core/agent/tools/tasks.py +454 -0
  61. emdash_core/agent/tools/traversal.py +588 -0
  62. emdash_core/agent/tools/web.py +179 -0
  63. emdash_core/analytics/__init__.py +5 -0
  64. emdash_core/analytics/engine.py +1286 -0
  65. emdash_core/api/__init__.py +5 -0
  66. emdash_core/api/agent.py +308 -0
  67. emdash_core/api/agents.py +154 -0
  68. emdash_core/api/analyze.py +264 -0
  69. emdash_core/api/auth.py +173 -0
  70. emdash_core/api/context.py +77 -0
  71. emdash_core/api/db.py +121 -0
  72. emdash_core/api/embed.py +131 -0
  73. emdash_core/api/feature.py +143 -0
  74. emdash_core/api/health.py +93 -0
  75. emdash_core/api/index.py +162 -0
  76. emdash_core/api/plan.py +110 -0
  77. emdash_core/api/projectmd.py +210 -0
  78. emdash_core/api/query.py +320 -0
  79. emdash_core/api/research.py +122 -0
  80. emdash_core/api/review.py +161 -0
  81. emdash_core/api/router.py +76 -0
  82. emdash_core/api/rules.py +116 -0
  83. emdash_core/api/search.py +119 -0
  84. emdash_core/api/spec.py +99 -0
  85. emdash_core/api/swarm.py +223 -0
  86. emdash_core/api/tasks.py +109 -0
  87. emdash_core/api/team.py +120 -0
  88. emdash_core/auth/__init__.py +17 -0
  89. emdash_core/auth/github.py +389 -0
  90. emdash_core/config.py +74 -0
  91. emdash_core/context/__init__.py +52 -0
  92. emdash_core/context/models.py +50 -0
  93. emdash_core/context/providers/__init__.py +11 -0
  94. emdash_core/context/providers/base.py +74 -0
  95. emdash_core/context/providers/explored_areas.py +183 -0
  96. emdash_core/context/providers/touched_areas.py +360 -0
  97. emdash_core/context/registry.py +73 -0
  98. emdash_core/context/reranker.py +199 -0
  99. emdash_core/context/service.py +260 -0
  100. emdash_core/context/session.py +352 -0
  101. emdash_core/core/__init__.py +104 -0
  102. emdash_core/core/config.py +454 -0
  103. emdash_core/core/exceptions.py +55 -0
  104. emdash_core/core/models.py +265 -0
  105. emdash_core/core/review_config.py +57 -0
  106. emdash_core/db/__init__.py +67 -0
  107. emdash_core/db/auth.py +134 -0
  108. emdash_core/db/models.py +91 -0
  109. emdash_core/db/provider.py +222 -0
  110. emdash_core/db/providers/__init__.py +5 -0
  111. emdash_core/db/providers/supabase.py +452 -0
  112. emdash_core/embeddings/__init__.py +24 -0
  113. emdash_core/embeddings/indexer.py +534 -0
  114. emdash_core/embeddings/models.py +192 -0
  115. emdash_core/embeddings/providers/__init__.py +7 -0
  116. emdash_core/embeddings/providers/base.py +112 -0
  117. emdash_core/embeddings/providers/fireworks.py +141 -0
  118. emdash_core/embeddings/providers/openai.py +104 -0
  119. emdash_core/embeddings/registry.py +146 -0
  120. emdash_core/embeddings/service.py +215 -0
  121. emdash_core/graph/__init__.py +26 -0
  122. emdash_core/graph/builder.py +134 -0
  123. emdash_core/graph/connection.py +692 -0
  124. emdash_core/graph/schema.py +416 -0
  125. emdash_core/graph/writer.py +667 -0
  126. emdash_core/ingestion/__init__.py +7 -0
  127. emdash_core/ingestion/change_detector.py +150 -0
  128. emdash_core/ingestion/git/__init__.py +5 -0
  129. emdash_core/ingestion/git/commit_analyzer.py +196 -0
  130. emdash_core/ingestion/github/__init__.py +6 -0
  131. emdash_core/ingestion/github/pr_fetcher.py +296 -0
  132. emdash_core/ingestion/github/task_extractor.py +100 -0
  133. emdash_core/ingestion/orchestrator.py +540 -0
  134. emdash_core/ingestion/parsers/__init__.py +10 -0
  135. emdash_core/ingestion/parsers/base_parser.py +66 -0
  136. emdash_core/ingestion/parsers/call_graph_builder.py +121 -0
  137. emdash_core/ingestion/parsers/class_extractor.py +154 -0
  138. emdash_core/ingestion/parsers/function_extractor.py +202 -0
  139. emdash_core/ingestion/parsers/import_analyzer.py +119 -0
  140. emdash_core/ingestion/parsers/python_parser.py +123 -0
  141. emdash_core/ingestion/parsers/registry.py +72 -0
  142. emdash_core/ingestion/parsers/ts_ast_parser.js +313 -0
  143. emdash_core/ingestion/parsers/typescript_parser.py +278 -0
  144. emdash_core/ingestion/repository.py +346 -0
  145. emdash_core/models/__init__.py +38 -0
  146. emdash_core/models/agent.py +68 -0
  147. emdash_core/models/index.py +77 -0
  148. emdash_core/models/query.py +113 -0
  149. emdash_core/planning/__init__.py +7 -0
  150. emdash_core/planning/agent_api.py +413 -0
  151. emdash_core/planning/context_builder.py +265 -0
  152. emdash_core/planning/feature_context.py +232 -0
  153. emdash_core/planning/feature_expander.py +646 -0
  154. emdash_core/planning/llm_explainer.py +198 -0
  155. emdash_core/planning/similarity.py +509 -0
  156. emdash_core/planning/team_focus.py +821 -0
  157. emdash_core/server.py +153 -0
  158. emdash_core/sse/__init__.py +5 -0
  159. emdash_core/sse/stream.py +196 -0
  160. emdash_core/swarm/__init__.py +17 -0
  161. emdash_core/swarm/merge_agent.py +383 -0
  162. emdash_core/swarm/session_manager.py +274 -0
  163. emdash_core/swarm/swarm_runner.py +226 -0
  164. emdash_core/swarm/task_definition.py +137 -0
  165. emdash_core/swarm/worker_spawner.py +319 -0
  166. emdash_core/swarm/worktree_manager.py +278 -0
  167. emdash_core/templates/__init__.py +10 -0
  168. emdash_core/templates/defaults/agent-builder.md.template +82 -0
  169. emdash_core/templates/defaults/focus.md.template +115 -0
  170. emdash_core/templates/defaults/pr-review-enhanced.md.template +309 -0
  171. emdash_core/templates/defaults/pr-review.md.template +80 -0
  172. emdash_core/templates/defaults/project.md.template +85 -0
  173. emdash_core/templates/defaults/research_critic.md.template +112 -0
  174. emdash_core/templates/defaults/research_planner.md.template +85 -0
  175. emdash_core/templates/defaults/research_synthesizer.md.template +128 -0
  176. emdash_core/templates/defaults/reviewer.md.template +81 -0
  177. emdash_core/templates/defaults/spec.md.template +41 -0
  178. emdash_core/templates/defaults/tasks.md.template +78 -0
  179. emdash_core/templates/loader.py +296 -0
  180. emdash_core/utils/__init__.py +45 -0
  181. emdash_core/utils/git.py +84 -0
  182. emdash_core/utils/image.py +502 -0
  183. emdash_core/utils/logger.py +51 -0
  184. emdash_core-0.1.7.dist-info/METADATA +35 -0
  185. emdash_core-0.1.7.dist-info/RECORD +187 -0
  186. emdash_core-0.1.7.dist-info/WHEEL +4 -0
  187. 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)