emdash-core 0.1.7__py3-none-any.whl → 0.1.25__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 +6 -1
- emdash_core/agent/events.py +29 -0
- emdash_core/agent/prompts/__init__.py +5 -0
- emdash_core/agent/prompts/main_agent.py +22 -2
- emdash_core/agent/prompts/plan_mode.py +126 -0
- emdash_core/agent/prompts/subagents.py +11 -7
- emdash_core/agent/prompts/workflow.py +138 -43
- emdash_core/agent/providers/base.py +4 -0
- emdash_core/agent/providers/models.py +7 -0
- emdash_core/agent/providers/openai_provider.py +74 -2
- emdash_core/agent/runner.py +556 -34
- emdash_core/agent/skills.py +319 -0
- emdash_core/agent/toolkit.py +48 -0
- emdash_core/agent/tools/__init__.py +3 -2
- emdash_core/agent/tools/modes.py +197 -53
- emdash_core/agent/tools/search.py +4 -0
- emdash_core/agent/tools/skill.py +193 -0
- emdash_core/agent/tools/spec.py +61 -94
- emdash_core/agent/tools/tasks.py +15 -78
- emdash_core/api/agent.py +7 -7
- emdash_core/api/index.py +1 -1
- emdash_core/api/projectmd.py +4 -2
- emdash_core/api/router.py +2 -0
- emdash_core/api/skills.py +241 -0
- emdash_core/checkpoint/__init__.py +40 -0
- emdash_core/checkpoint/cli.py +175 -0
- emdash_core/checkpoint/git_operations.py +250 -0
- emdash_core/checkpoint/manager.py +231 -0
- emdash_core/checkpoint/models.py +107 -0
- emdash_core/checkpoint/storage.py +201 -0
- emdash_core/config.py +1 -1
- emdash_core/core/config.py +18 -2
- emdash_core/graph/schema.py +5 -5
- emdash_core/ingestion/orchestrator.py +19 -10
- emdash_core/models/agent.py +1 -1
- emdash_core/server.py +42 -0
- emdash_core/sse/stream.py +1 -0
- {emdash_core-0.1.7.dist-info → emdash_core-0.1.25.dist-info}/METADATA +1 -2
- {emdash_core-0.1.7.dist-info → emdash_core-0.1.25.dist-info}/RECORD +41 -31
- {emdash_core-0.1.7.dist-info → emdash_core-0.1.25.dist-info}/entry_points.txt +1 -0
- {emdash_core-0.1.7.dist-info → emdash_core-0.1.25.dist-info}/WHEEL +0 -0
emdash_core/agent/tools/spec.py
CHANGED
|
@@ -77,23 +77,41 @@ Creates a structured spec document with requirements and acceptance criteria."""
|
|
|
77
77
|
ToolResult with spec info
|
|
78
78
|
"""
|
|
79
79
|
try:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
# Build markdown content from structured fields
|
|
81
|
+
content_parts = []
|
|
82
|
+
|
|
83
|
+
if summary:
|
|
84
|
+
content_parts.append(f"> {summary}\n")
|
|
85
|
+
|
|
86
|
+
if requirements:
|
|
87
|
+
content_parts.append("## Requirements")
|
|
88
|
+
content_parts.extend(f"- {req}" for req in requirements)
|
|
89
|
+
content_parts.append("")
|
|
90
|
+
|
|
91
|
+
if acceptance_criteria:
|
|
92
|
+
content_parts.append("## Acceptance Criteria")
|
|
93
|
+
content_parts.extend(f"- {crit}" for crit in acceptance_criteria)
|
|
94
|
+
content_parts.append("")
|
|
95
|
+
|
|
96
|
+
if technical_notes:
|
|
97
|
+
content_parts.append("## Technical Notes")
|
|
98
|
+
content_parts.extend(f"- {note}" for note in technical_notes)
|
|
99
|
+
content_parts.append("")
|
|
100
|
+
|
|
101
|
+
if dependencies:
|
|
102
|
+
content_parts.append("## Dependencies")
|
|
103
|
+
content_parts.extend(f"- {dep}" for dep in dependencies)
|
|
104
|
+
content_parts.append("")
|
|
105
|
+
|
|
106
|
+
if open_questions:
|
|
107
|
+
content_parts.append("## Open Questions")
|
|
108
|
+
content_parts.extend(f"- {q}" for q in open_questions)
|
|
109
|
+
content_parts.append("")
|
|
89
110
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
f"Spec validation failed: {', '.join(errors)}",
|
|
95
|
-
suggestions=["Ensure all required fields are provided"],
|
|
96
|
-
)
|
|
111
|
+
content = "\n".join(content_parts)
|
|
112
|
+
|
|
113
|
+
# Create spec with title and content only (matches Spec schema)
|
|
114
|
+
spec = Spec(title=title, content=content)
|
|
97
115
|
|
|
98
116
|
# Store in state
|
|
99
117
|
state = SpecState.get_instance()
|
|
@@ -195,14 +213,8 @@ Returns the spec in markdown format."""
|
|
|
195
213
|
return ToolResult.success_result(
|
|
196
214
|
data={
|
|
197
215
|
"title": spec.title,
|
|
198
|
-
"
|
|
199
|
-
"requirements": spec.requirements,
|
|
200
|
-
"acceptance_criteria": spec.acceptance_criteria,
|
|
201
|
-
"technical_notes": spec.technical_notes,
|
|
202
|
-
"dependencies": spec.dependencies,
|
|
203
|
-
"open_questions": spec.open_questions,
|
|
216
|
+
"content": spec.content,
|
|
204
217
|
"markdown": spec.to_markdown(),
|
|
205
|
-
"is_complete": spec.is_complete(),
|
|
206
218
|
},
|
|
207
219
|
)
|
|
208
220
|
|
|
@@ -216,7 +228,7 @@ class UpdateSpecTool(BaseTool):
|
|
|
216
228
|
|
|
217
229
|
name = "update_spec"
|
|
218
230
|
description = """Update the current feature specification.
|
|
219
|
-
|
|
231
|
+
Append content or replace the entire spec content."""
|
|
220
232
|
category = ToolCategory.PLANNING
|
|
221
233
|
|
|
222
234
|
def __init__(self, connection=None):
|
|
@@ -225,24 +237,17 @@ Add or modify requirements, criteria, or other fields."""
|
|
|
225
237
|
|
|
226
238
|
def execute(
|
|
227
239
|
self,
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
add_open_questions: Optional[list[str]] = None,
|
|
233
|
-
resolve_questions: Optional[list[str]] = None,
|
|
234
|
-
update_summary: Optional[str] = None,
|
|
240
|
+
append_content: Optional[str] = None,
|
|
241
|
+
replace_content: Optional[str] = None,
|
|
242
|
+
update_title: Optional[str] = None,
|
|
243
|
+
**kwargs,
|
|
235
244
|
) -> ToolResult:
|
|
236
245
|
"""Update the current spec.
|
|
237
246
|
|
|
238
247
|
Args:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
add_dependencies: Dependencies to add
|
|
243
|
-
add_open_questions: Questions to add
|
|
244
|
-
resolve_questions: Questions to mark as resolved
|
|
245
|
-
update_summary: New summary text
|
|
248
|
+
append_content: Content to append to existing spec
|
|
249
|
+
replace_content: Content to replace entire spec content
|
|
250
|
+
update_title: New title for the spec
|
|
246
251
|
|
|
247
252
|
Returns:
|
|
248
253
|
ToolResult with updated spec
|
|
@@ -257,28 +262,15 @@ Add or modify requirements, criteria, or other fields."""
|
|
|
257
262
|
|
|
258
263
|
spec = state.current_spec
|
|
259
264
|
|
|
260
|
-
#
|
|
261
|
-
if
|
|
262
|
-
spec.
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if
|
|
266
|
-
spec.
|
|
267
|
-
|
|
268
|
-
spec.
|
|
269
|
-
if add_open_questions:
|
|
270
|
-
spec.open_questions.extend(add_open_questions)
|
|
271
|
-
|
|
272
|
-
# Resolve questions
|
|
273
|
-
if resolve_questions:
|
|
274
|
-
spec.open_questions = [
|
|
275
|
-
q for q in spec.open_questions
|
|
276
|
-
if q not in resolve_questions
|
|
277
|
-
]
|
|
278
|
-
|
|
279
|
-
# Update summary
|
|
280
|
-
if update_summary:
|
|
281
|
-
spec.summary = update_summary
|
|
265
|
+
# Update title if provided
|
|
266
|
+
if update_title:
|
|
267
|
+
spec.title = update_title
|
|
268
|
+
|
|
269
|
+
# Replace or append content
|
|
270
|
+
if replace_content is not None:
|
|
271
|
+
spec.content = replace_content
|
|
272
|
+
elif append_content:
|
|
273
|
+
spec.content = spec.content + "\n\n" + append_content
|
|
282
274
|
|
|
283
275
|
# Save if configured
|
|
284
276
|
if state.save_path:
|
|
@@ -290,10 +282,7 @@ Add or modify requirements, criteria, or other fields."""
|
|
|
290
282
|
return ToolResult.success_result(
|
|
291
283
|
data={
|
|
292
284
|
"title": spec.title,
|
|
293
|
-
"
|
|
294
|
-
"acceptance_criteria_count": len(spec.acceptance_criteria),
|
|
295
|
-
"open_questions_count": len(spec.open_questions),
|
|
296
|
-
"is_complete": spec.is_complete(),
|
|
285
|
+
"content": spec.content,
|
|
297
286
|
"markdown": spec.to_markdown(),
|
|
298
287
|
},
|
|
299
288
|
)
|
|
@@ -302,39 +291,17 @@ Add or modify requirements, criteria, or other fields."""
|
|
|
302
291
|
"""Get OpenAI function schema."""
|
|
303
292
|
return self._make_schema(
|
|
304
293
|
properties={
|
|
305
|
-
"
|
|
306
|
-
"type": "
|
|
307
|
-
"
|
|
308
|
-
"description": "Requirements to add",
|
|
309
|
-
},
|
|
310
|
-
"add_acceptance_criteria": {
|
|
311
|
-
"type": "array",
|
|
312
|
-
"items": {"type": "string"},
|
|
313
|
-
"description": "Acceptance criteria to add",
|
|
314
|
-
},
|
|
315
|
-
"add_technical_notes": {
|
|
316
|
-
"type": "array",
|
|
317
|
-
"items": {"type": "string"},
|
|
318
|
-
"description": "Technical notes to add",
|
|
319
|
-
},
|
|
320
|
-
"add_dependencies": {
|
|
321
|
-
"type": "array",
|
|
322
|
-
"items": {"type": "string"},
|
|
323
|
-
"description": "Dependencies to add",
|
|
324
|
-
},
|
|
325
|
-
"add_open_questions": {
|
|
326
|
-
"type": "array",
|
|
327
|
-
"items": {"type": "string"},
|
|
328
|
-
"description": "Open questions to add",
|
|
294
|
+
"append_content": {
|
|
295
|
+
"type": "string",
|
|
296
|
+
"description": "Markdown content to append to existing spec",
|
|
329
297
|
},
|
|
330
|
-
"
|
|
331
|
-
"type": "
|
|
332
|
-
"
|
|
333
|
-
"description": "Questions to mark as resolved",
|
|
298
|
+
"replace_content": {
|
|
299
|
+
"type": "string",
|
|
300
|
+
"description": "Markdown content to replace entire spec content",
|
|
334
301
|
},
|
|
335
|
-
"
|
|
302
|
+
"update_title": {
|
|
336
303
|
"type": "string",
|
|
337
|
-
"description": "New
|
|
304
|
+
"description": "New title for the spec",
|
|
338
305
|
},
|
|
339
306
|
},
|
|
340
307
|
required=[],
|
emdash_core/agent/tools/tasks.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Task management tools for agent workflows."""
|
|
2
2
|
|
|
3
|
-
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
@@ -23,9 +23,6 @@ class Task:
|
|
|
23
23
|
title: str
|
|
24
24
|
description: str = ""
|
|
25
25
|
status: TaskStatus = TaskStatus.PENDING
|
|
26
|
-
complexity: str = "M" # T-shirt size: S, M, L, XL
|
|
27
|
-
files: list[str] = field(default_factory=list) # Target files for this task
|
|
28
|
-
checklist: list[dict] = field(default_factory=list) # Subtasks: [{text, done}]
|
|
29
26
|
|
|
30
27
|
def to_dict(self) -> dict:
|
|
31
28
|
return {
|
|
@@ -33,9 +30,6 @@ class Task:
|
|
|
33
30
|
"title": self.title,
|
|
34
31
|
"description": self.description,
|
|
35
32
|
"status": self.status.value,
|
|
36
|
-
"complexity": self.complexity,
|
|
37
|
-
"files": self.files,
|
|
38
|
-
"checklist": self.checklist,
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
|
|
@@ -68,26 +62,17 @@ class TaskState:
|
|
|
68
62
|
self,
|
|
69
63
|
title: str,
|
|
70
64
|
description: str = "",
|
|
71
|
-
complexity: str = "M",
|
|
72
|
-
files: list[str] = None,
|
|
73
|
-
checklist: list[str] = None,
|
|
74
65
|
) -> Task:
|
|
75
66
|
"""Add a new task.
|
|
76
67
|
|
|
77
68
|
Args:
|
|
78
69
|
title: Task title
|
|
79
70
|
description: Detailed description
|
|
80
|
-
complexity: T-shirt size (S, M, L, XL)
|
|
81
|
-
files: List of target file paths
|
|
82
|
-
checklist: List of subtask strings (converted to {text, done} dicts)
|
|
83
71
|
"""
|
|
84
72
|
task = Task(
|
|
85
73
|
id=str(self._next_id),
|
|
86
74
|
title=title,
|
|
87
75
|
description=description,
|
|
88
|
-
complexity=complexity,
|
|
89
|
-
files=files or [],
|
|
90
|
-
checklist=[{"text": item, "done": False} for item in (checklist or [])],
|
|
91
76
|
)
|
|
92
77
|
self._next_id += 1
|
|
93
78
|
self.tasks.append(task)
|
|
@@ -139,18 +124,15 @@ class TaskManagementTool(BaseTool):
|
|
|
139
124
|
|
|
140
125
|
|
|
141
126
|
class WriteTodoTool(TaskManagementTool):
|
|
142
|
-
"""Create a new
|
|
127
|
+
"""Create a new task for tracking work."""
|
|
143
128
|
|
|
144
129
|
name = "write_todo"
|
|
145
|
-
description = "Create a new task
|
|
130
|
+
description = "Create a new task. Use reset=true to clear all existing tasks first."
|
|
146
131
|
|
|
147
132
|
def execute(
|
|
148
133
|
self,
|
|
149
134
|
title: str,
|
|
150
135
|
description: str = "",
|
|
151
|
-
complexity: str = "M",
|
|
152
|
-
files: list[str] = None,
|
|
153
|
-
checklist: list[str] = None,
|
|
154
136
|
reset: bool = False,
|
|
155
137
|
**kwargs,
|
|
156
138
|
) -> ToolResult:
|
|
@@ -159,9 +141,6 @@ class WriteTodoTool(TaskManagementTool):
|
|
|
159
141
|
Args:
|
|
160
142
|
title: Short task title
|
|
161
143
|
description: Detailed description (optional)
|
|
162
|
-
complexity: T-shirt size (S, M, L, XL)
|
|
163
|
-
files: Target file paths this task will modify
|
|
164
|
-
checklist: List of subtask items to track
|
|
165
144
|
reset: If true, clear all existing tasks before adding this one
|
|
166
145
|
|
|
167
146
|
Returns:
|
|
@@ -177,9 +156,6 @@ class WriteTodoTool(TaskManagementTool):
|
|
|
177
156
|
task = self.state.add_task(
|
|
178
157
|
title=title.strip(),
|
|
179
158
|
description=description.strip() if description else "",
|
|
180
|
-
complexity=complexity,
|
|
181
|
-
files=files or [],
|
|
182
|
-
checklist=checklist or [],
|
|
183
159
|
)
|
|
184
160
|
|
|
185
161
|
return ToolResult.success_result({
|
|
@@ -201,21 +177,6 @@ class WriteTodoTool(TaskManagementTool):
|
|
|
201
177
|
"type": "string",
|
|
202
178
|
"description": "Detailed description of what needs to be done",
|
|
203
179
|
},
|
|
204
|
-
"complexity": {
|
|
205
|
-
"type": "string",
|
|
206
|
-
"enum": ["S", "M", "L", "XL"],
|
|
207
|
-
"description": "T-shirt size complexity: S (trivial), M (moderate), L (significant), XL (complex)",
|
|
208
|
-
},
|
|
209
|
-
"files": {
|
|
210
|
-
"type": "array",
|
|
211
|
-
"items": {"type": "string"},
|
|
212
|
-
"description": "Target file paths this task will modify",
|
|
213
|
-
},
|
|
214
|
-
"checklist": {
|
|
215
|
-
"type": "array",
|
|
216
|
-
"items": {"type": "string"},
|
|
217
|
-
"description": "List of subtask items to track (e.g., ['Add imports', 'Update function', 'Add tests'])",
|
|
218
|
-
},
|
|
219
180
|
"reset": {
|
|
220
181
|
"type": "boolean",
|
|
221
182
|
"description": "Set to true to clear all existing tasks before adding this one",
|
|
@@ -227,39 +188,30 @@ class WriteTodoTool(TaskManagementTool):
|
|
|
227
188
|
|
|
228
189
|
|
|
229
190
|
class UpdateTodoListTool(TaskManagementTool):
|
|
230
|
-
"""Update task status
|
|
191
|
+
"""Update task status."""
|
|
231
192
|
|
|
232
193
|
name = "update_todo_list"
|
|
233
|
-
description = "Update task status
|
|
194
|
+
description = "Update task status. Auto-creates tasks if they don't exist."
|
|
234
195
|
|
|
235
196
|
def execute(
|
|
236
197
|
self,
|
|
237
198
|
task_id: str,
|
|
238
199
|
status: str = None,
|
|
239
|
-
checklist_done: list[int] = None,
|
|
240
|
-
checklist: list[int] = None, # Alias for checklist_done
|
|
241
|
-
files: list[str] = None,
|
|
242
200
|
title: str = "",
|
|
243
201
|
description: str = "",
|
|
244
202
|
**kwargs, # Ignore unexpected params from LLM
|
|
245
203
|
) -> ToolResult:
|
|
246
|
-
"""Update task status
|
|
204
|
+
"""Update task status.
|
|
247
205
|
|
|
248
206
|
Args:
|
|
249
207
|
task_id: Task ID to update (e.g., "1", "2")
|
|
250
208
|
status: New status (pending, in_progress, completed)
|
|
251
|
-
checklist_done: Indices of checklist items to mark done (0-based)
|
|
252
|
-
checklist: Alias for checklist_done
|
|
253
|
-
files: Additional files to add to the task
|
|
254
209
|
title: Optional title for auto-created tasks
|
|
255
210
|
description: Optional description for auto-created tasks
|
|
256
211
|
|
|
257
212
|
Returns:
|
|
258
213
|
ToolResult with updated task list
|
|
259
214
|
"""
|
|
260
|
-
# Handle checklist alias
|
|
261
|
-
if checklist and not checklist_done:
|
|
262
|
-
checklist_done = checklist
|
|
263
215
|
task = self.state.get_task(task_id)
|
|
264
216
|
|
|
265
217
|
# Auto-create task if not found
|
|
@@ -276,7 +228,6 @@ class UpdateTodoListTool(TaskManagementTool):
|
|
|
276
228
|
title=title or f"Task {task_id}",
|
|
277
229
|
status=new_status,
|
|
278
230
|
description=description,
|
|
279
|
-
files=files or [],
|
|
280
231
|
)
|
|
281
232
|
self.state.tasks.append(task)
|
|
282
233
|
return ToolResult.success_result({
|
|
@@ -295,18 +246,6 @@ class UpdateTodoListTool(TaskManagementTool):
|
|
|
295
246
|
f"Invalid status: {status}. Use: pending, in_progress, completed"
|
|
296
247
|
)
|
|
297
248
|
|
|
298
|
-
# Mark checklist items as done
|
|
299
|
-
if checklist_done:
|
|
300
|
-
for idx in checklist_done:
|
|
301
|
-
if 0 <= idx < len(task.checklist):
|
|
302
|
-
task.checklist[idx]["done"] = True
|
|
303
|
-
|
|
304
|
-
# Add files
|
|
305
|
-
if files:
|
|
306
|
-
for f in files:
|
|
307
|
-
if f not in task.files:
|
|
308
|
-
task.files.append(f)
|
|
309
|
-
|
|
310
249
|
return ToolResult.success_result({
|
|
311
250
|
"task_id": task_id,
|
|
312
251
|
"task": task.to_dict(),
|
|
@@ -326,16 +265,6 @@ class UpdateTodoListTool(TaskManagementTool):
|
|
|
326
265
|
"enum": ["pending", "in_progress", "completed"],
|
|
327
266
|
"description": "New status for the task",
|
|
328
267
|
},
|
|
329
|
-
"checklist_done": {
|
|
330
|
-
"type": "array",
|
|
331
|
-
"items": {"type": "integer"},
|
|
332
|
-
"description": "Indices of checklist items to mark done (0-based)",
|
|
333
|
-
},
|
|
334
|
-
"files": {
|
|
335
|
-
"type": "array",
|
|
336
|
-
"items": {"type": "string"},
|
|
337
|
-
"description": "Additional file paths to add to the task",
|
|
338
|
-
},
|
|
339
268
|
"title": {
|
|
340
269
|
"type": "string",
|
|
341
270
|
"description": "Task title (used if auto-creating)",
|
|
@@ -353,7 +282,13 @@ class AskFollowupQuestionTool(TaskManagementTool):
|
|
|
353
282
|
"""Request clarification from the user."""
|
|
354
283
|
|
|
355
284
|
name = "ask_followup_question"
|
|
356
|
-
description = "Ask the user a clarifying question
|
|
285
|
+
description = """Ask the user a clarifying question when you need more information to proceed.
|
|
286
|
+
|
|
287
|
+
CRITICAL CONSTRAINTS:
|
|
288
|
+
- Only ask ONE question at a time - never call this tool multiple times in parallel
|
|
289
|
+
- Only ask AFTER doing research first (read files, search code, explore the codebase)
|
|
290
|
+
- Questions should be informed by what you've learned, not generic upfront questionnaires
|
|
291
|
+
- If you need multiple pieces of information, ask the most important one first"""
|
|
357
292
|
|
|
358
293
|
def execute(
|
|
359
294
|
self,
|
|
@@ -452,3 +387,5 @@ class AttemptCompletionTool(TaskManagementTool):
|
|
|
452
387
|
},
|
|
453
388
|
required=["summary"],
|
|
454
389
|
)
|
|
390
|
+
|
|
391
|
+
|
emdash_core/api/agent.py
CHANGED
|
@@ -73,6 +73,13 @@ def _run_agent_sync(
|
|
|
73
73
|
emitter=emitter,
|
|
74
74
|
)
|
|
75
75
|
|
|
76
|
+
# Store session state BEFORE running (so it exists even if interrupted)
|
|
77
|
+
_sessions[session_id] = {
|
|
78
|
+
"runner": runner,
|
|
79
|
+
"message_count": 1,
|
|
80
|
+
"model": model,
|
|
81
|
+
}
|
|
82
|
+
|
|
76
83
|
# Convert image data if provided
|
|
77
84
|
agent_images = None
|
|
78
85
|
if images:
|
|
@@ -85,13 +92,6 @@ def _run_agent_sync(
|
|
|
85
92
|
# Run the agent
|
|
86
93
|
response = runner.run(message, images=agent_images)
|
|
87
94
|
|
|
88
|
-
# Store session state
|
|
89
|
-
_sessions[session_id] = {
|
|
90
|
-
"runner": runner,
|
|
91
|
-
"message_count": 1,
|
|
92
|
-
"model": model,
|
|
93
|
-
}
|
|
94
|
-
|
|
95
95
|
return response
|
|
96
96
|
|
|
97
97
|
except Exception as e:
|
emdash_core/api/index.py
CHANGED
|
@@ -64,7 +64,7 @@ def _run_index_sync(
|
|
|
64
64
|
# Create orchestrator (uses configured connection)
|
|
65
65
|
orchestrator = IngestionOrchestrator()
|
|
66
66
|
|
|
67
|
-
sse_handler.emit(EventType.PROGRESS, {"step": "
|
|
67
|
+
sse_handler.emit(EventType.PROGRESS, {"step": "Indexing codebase", "percent": 10})
|
|
68
68
|
|
|
69
69
|
# Progress callback to emit SSE events during parsing
|
|
70
70
|
def progress_callback(step: str, percent: float):
|
emdash_core/api/projectmd.py
CHANGED
|
@@ -105,7 +105,7 @@ def _generate_projectmd_sync(
|
|
|
105
105
|
runner = AgentRunner(
|
|
106
106
|
model=model,
|
|
107
107
|
verbose=True,
|
|
108
|
-
max_iterations=
|
|
108
|
+
max_iterations=100,
|
|
109
109
|
emitter=emitter,
|
|
110
110
|
)
|
|
111
111
|
|
|
@@ -116,7 +116,9 @@ def _generate_projectmd_sync(
|
|
|
116
116
|
3. Key files and their purposes
|
|
117
117
|
4. How to get started
|
|
118
118
|
|
|
119
|
-
Use the available tools to explore the codebase
|
|
119
|
+
Use the available tools to explore the codebase structure and key files.
|
|
120
|
+
After exploration, write a comprehensive PROJECT.md document.
|
|
121
|
+
IMPORTANT: After exploring, output the complete PROJECT.md content as your final response."""
|
|
120
122
|
|
|
121
123
|
content = runner.run(prompt)
|
|
122
124
|
|
emdash_core/api/router.py
CHANGED
|
@@ -24,6 +24,7 @@ from . import (
|
|
|
24
24
|
context,
|
|
25
25
|
feature,
|
|
26
26
|
projectmd,
|
|
27
|
+
skills,
|
|
27
28
|
)
|
|
28
29
|
|
|
29
30
|
api_router = APIRouter(prefix="/api")
|
|
@@ -37,6 +38,7 @@ api_router.include_router(auth.router)
|
|
|
37
38
|
# Agent operations
|
|
38
39
|
api_router.include_router(agent.router)
|
|
39
40
|
api_router.include_router(agents.router)
|
|
41
|
+
api_router.include_router(skills.router)
|
|
40
42
|
|
|
41
43
|
# Database management
|
|
42
44
|
api_router.include_router(db.router)
|