Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion apps/inference/src/claudebench_inference/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,16 @@ def build_context_prompt(self, subtaskId: str, specialist: str, subtask: Dict[st
description = subtask.get('description', 'No description provided')
dependencies = subtask.get('dependencies', [])
constraints = subtask.get('context', {}).get('constraints', [])
# Extract attachments from subtask data
attachments = subtask.get('attachments', [])

return template.render(
subtaskId=subtaskId,
specialist=specialist,
description=description,
dependencies=dependencies,
constraints=constraints
constraints=constraints,
attachments=attachments
)

def build_conflict_prompt(self, solutions: List[ConflictSolution], context: ConflictContext) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,32 @@ PROJECT CONSTRAINTS:
{% endfor %}
{% endif %}

{% if attachments and attachments|length > 0 %}
TASK ATTACHMENTS (Important Context):
{% for attachment in attachments %}
- {{ attachment.key }} ({{ attachment.type }}):
{% if attachment.type == 'json' and attachment.value %}
{% if attachment.key == 'result' or 'test-results' in attachment.key %}
Previous Results: {{ attachment.value | tojson(indent=2) }}
{% elif 'git-commit-' in attachment.key %}
Git Commit Info: {{ attachment.value | tojson(indent=2) }}
{% elif 'context_' in attachment.key %}
Previous Context: {{ attachment.value | tojson(indent=2) }}
{% elif attachment.key == 'error-details' %}
Error Information: {{ attachment.value | tojson(indent=2) }}
{% else %}
Content: {{ attachment.value | tojson(indent=2) }}
{% endif %}
{% elif attachment.type == 'markdown' and attachment.content %}
Content: {{ attachment.content }}
{% elif attachment.type == 'text' and attachment.content %}
Content: {{ attachment.content }}
{% elif attachment.type == 'url' and attachment.url %}
URL: {{ attachment.url }}
{% endif %}
{% endfor %}
{% endif %}

IMPORTANT: You have a LIMITED number of turns to complete your exploration and provide the JSON response.
EFFICIENCY TIP: Use multiple tools in parallel to maximize efficiency:
- Read multiple files in a single turn (e.g., Read file1, file2, file3 simultaneously)
Expand Down
37 changes: 35 additions & 2 deletions apps/server/src/handlers/task/task.context.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,18 @@ export class TaskContextHandler {
const taskKey = `cb:task:${input.taskId}`;
const taskData = await redis.pub.hgetall(taskKey);

// Store attachments separately since they come from DB
let taskAttachments: any[] = [];

if (!taskData || Object.keys(taskData).length === 0) {
// Try to fetch from database
if (ctx.prisma) {
const task = await ctx.prisma.task.findUnique({
where: { id: input.taskId },
include: {
attachments: {
where: { type: "json" },
take: 5
orderBy: { createdAt: 'desc' },
take: 10 // Increased from 5 to get more context
}
}
});
Expand All @@ -106,6 +109,9 @@ export class TaskContextHandler {
throw new Error(`Task ${input.taskId} not found`);
}

// Store attachments for later use
taskAttachments = task.attachments || [];

// Use database data
taskData.text = task.text;
taskData.status = task.status;
Expand All @@ -115,8 +121,33 @@ export class TaskContextHandler {
} else {
throw new Error(`Task ${input.taskId} not found`);
}
} else {
// Task found in Redis, but we still need to fetch attachments from DB
if (ctx.prisma) {
const attachments = await ctx.prisma.taskAttachment.findMany({
where: { taskId: input.taskId },
orderBy: { createdAt: 'desc' },
take: 10
});
taskAttachments = attachments || [];
}
}

// Process attachments to extract meaningful content
const processedAttachments = taskAttachments.map(att => ({
key: att.key,
type: att.type,
createdAt: att.createdAt,
// Parse JSON values for json type attachments
value: att.type === 'json' && att.value ?
(typeof att.value === 'string' ? JSON.parse(att.value) : att.value) :
att.value,
// Include content for text/markdown attachments
content: att.content || null,
// Include URL for url type attachments
url: att.url || null
}));

// Prepare task info for context generation
const taskInfo = {
id: input.taskId,
Expand All @@ -125,6 +156,7 @@ export class TaskContextHandler {
status: taskData.status,
priority: parseInt(taskData.priority || "50"),
metadata: taskData.metadata ? JSON.parse(taskData.metadata) : {},
attachments: processedAttachments, // Include processed attachments
constraints: input.constraints || [],
requirements: input.requirements || [],
existingFiles: input.existingFiles || [],
Expand Down Expand Up @@ -164,6 +196,7 @@ export class TaskContextHandler {
// Generate the prompt for the specialist
const contextData = {
...response,
attachments: processedAttachments, // Add attachments to context
customConstraints: input.constraints,
customRequirements: input.requirements,
existingFiles: input.existingFiles,
Expand Down
25 changes: 18 additions & 7 deletions apps/server/src/handlers/task/task.get_project.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,24 @@ export class TaskGetProjectHandler {
throw new Error(`Parent task ${parentTaskId} not found`);
}

// Fetch all subtasks for this project
// Fetch all subtasks for this project (excluding the parent task)
const subtasks = await ctx.prisma.task.findMany({
where: {
metadata: {
path: ["projectId"],
equals: projectId
}
AND: [
{
metadata: {
path: ["projectId"],
equals: projectId
}
},
{
// Only include actual subtasks - they have type: "subtask"
metadata: {
path: ["type"],
equals: "subtask"
}
}
]
},
include: {
attachments: {
Expand All @@ -99,8 +110,8 @@ export class TaskGetProjectHandler {
orderBy: { createdAt: "asc" }
});

// Filter out the parent task from subtasks
const actualSubtasks = subtasks.filter(t => t.id !== parentTaskId);
// Subtasks are already filtered by type
const actualSubtasks = subtasks;

// Get project metadata from Redis cache or attachments
const projectKey = `cb:project:${projectId}`;
Expand Down
49 changes: 49 additions & 0 deletions apps/server/src/templates/task/task-context-prompt.njk
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,55 @@ You must review these files before implementation:
{% endfor %}
{% endif %}

{% if attachments and attachments.length > 0 %}
## Task Attachments
The following attachments provide important context for this task:
{% for attachment in attachments %}

### {{ attachment.key }}
- **Type:** {{ attachment.type }}
- **Created:** {{ attachment.createdAt }}
{% if attachment.type == "json" and attachment.value %}
{% if attachment.key == "result" or attachment.key.startsWith("test-results") %}
**Previous Results:**
```json
{{ attachment.value | dump(2) }}
```
{% elif attachment.key.startsWith("git-commit-") %}
**Git Commit Information:**
```json
{{ attachment.value | dump(2) }}
```
{% elif attachment.key.startsWith("context_") %}
**Previous Context Generation:**
```json
{{ attachment.value | dump(2) }}
```
{% elif attachment.key == "error-details" %}
**Error Information:**
```json
{{ attachment.value | dump(2) }}
```
{% else %}
**Content:**
```json
{{ attachment.value | dump(2) }}
```
{% endif %}
{% elif attachment.type == "markdown" and attachment.content %}
**Content:**
{{ attachment.content }}
{% elif attachment.type == "text" and attachment.content %}
**Content:**
```
{{ attachment.content }}
```
{% elif attachment.type == "url" and attachment.url %}
**URL:** {{ attachment.url }}
{% endif %}
{% endfor %}
{% endif %}

{% if relatedWork and relatedWork.length > 0 %}
## Related Work
Other work in progress that may affect your implementation:
Expand Down