@synergenius/flow-weaver-pack-weaver 0.9.59 → 0.9.77
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.
- package/dist/ai-chat-provider.d.ts +12 -0
- package/dist/ai-chat-provider.d.ts.map +1 -1
- package/dist/ai-chat-provider.js +351 -335
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/agent-loop.d.ts +20 -0
- package/dist/bot/agent-loop.d.ts.map +1 -0
- package/dist/bot/agent-loop.js +331 -0
- package/dist/bot/agent-loop.js.map +1 -0
- package/dist/bot/ai-router.d.ts +19 -0
- package/dist/bot/ai-router.d.ts.map +1 -0
- package/dist/bot/ai-router.js +104 -0
- package/dist/bot/ai-router.js.map +1 -0
- package/dist/bot/assistant-tools.d.ts.map +1 -1
- package/dist/bot/assistant-tools.js +49 -33
- package/dist/bot/assistant-tools.js.map +1 -1
- package/dist/bot/async-mutex.d.ts +13 -0
- package/dist/bot/async-mutex.d.ts.map +1 -0
- package/dist/bot/async-mutex.js +37 -0
- package/dist/bot/async-mutex.js.map +1 -0
- package/dist/bot/bot-manager.d.ts +2 -2
- package/dist/bot/bot-manager.d.ts.map +1 -1
- package/dist/bot/bot-manager.js +3 -3
- package/dist/bot/bot-manager.js.map +1 -1
- package/dist/bot/bot-registry.js +2 -2
- package/dist/bot/bot-registry.js.map +1 -1
- package/dist/bot/conversation-store.d.ts +1 -0
- package/dist/bot/conversation-store.d.ts.map +1 -1
- package/dist/bot/conversation-store.js.map +1 -1
- package/dist/bot/dashboard.d.ts.map +1 -1
- package/dist/bot/dashboard.js +17 -8
- package/dist/bot/dashboard.js.map +1 -1
- package/dist/bot/improve-loop.js.map +1 -1
- package/dist/bot/index.d.ts +2 -4
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +1 -2
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/instance-manager.d.ts +31 -0
- package/dist/bot/instance-manager.d.ts.map +1 -0
- package/dist/bot/instance-manager.js +115 -0
- package/dist/bot/instance-manager.js.map +1 -0
- package/dist/bot/orchestrator.d.ts +36 -0
- package/dist/bot/orchestrator.d.ts.map +1 -0
- package/dist/bot/orchestrator.js +176 -0
- package/dist/bot/orchestrator.js.map +1 -0
- package/dist/bot/profile-store.d.ts +36 -0
- package/dist/bot/profile-store.d.ts.map +1 -0
- package/dist/bot/profile-store.js +208 -0
- package/dist/bot/profile-store.js.map +1 -0
- package/dist/bot/profile-types.d.ts +126 -0
- package/dist/bot/profile-types.d.ts.map +1 -0
- package/dist/bot/profile-types.js +7 -0
- package/dist/bot/profile-types.js.map +1 -0
- package/dist/bot/run-store.d.ts.map +1 -1
- package/dist/bot/run-store.js +8 -0
- package/dist/bot/run-store.js.map +1 -1
- package/dist/bot/runner.d.ts +4 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +5 -1
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/swarm-controller.d.ts +109 -0
- package/dist/bot/swarm-controller.d.ts.map +1 -0
- package/dist/bot/swarm-controller.js +640 -0
- package/dist/bot/swarm-controller.js.map +1 -0
- package/dist/bot/swarm-event-log.d.ts +28 -0
- package/dist/bot/swarm-event-log.d.ts.map +1 -0
- package/dist/bot/swarm-event-log.js +54 -0
- package/dist/bot/swarm-event-log.js.map +1 -0
- package/dist/bot/task-prompt-builder.d.ts +22 -0
- package/dist/bot/task-prompt-builder.d.ts.map +1 -0
- package/dist/bot/task-prompt-builder.js +240 -0
- package/dist/bot/task-prompt-builder.js.map +1 -0
- package/dist/bot/task-store.d.ts +21 -0
- package/dist/bot/task-store.d.ts.map +1 -0
- package/dist/bot/task-store.js +364 -0
- package/dist/bot/task-store.js.map +1 -0
- package/dist/bot/task-types.d.ts +79 -0
- package/dist/bot/task-types.d.ts.map +1 -0
- package/dist/bot/task-types.js +6 -0
- package/dist/bot/task-types.js.map +1 -0
- package/dist/bot/types.d.ts +8 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +79 -54
- package/dist/cli-handlers.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +749 -0
- package/dist/cli.js.map +1 -0
- package/dist/docs/docs/weaver-bot-usage.md +35 -18
- package/dist/docs/docs/weaver-config.md +20 -0
- package/dist/docs/docs/weaver-task-queue.md +31 -19
- package/dist/docs/weaver-config.md +15 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-tools.d.ts +17 -0
- package/dist/mcp-tools.d.ts.map +1 -1
- package/dist/mcp-tools.js +98 -279
- package/dist/mcp-tools.js.map +1 -1
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +6 -24
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/orchestrator-dispatch.d.ts +17 -0
- package/dist/node-types/orchestrator-dispatch.d.ts.map +1 -0
- package/dist/node-types/orchestrator-dispatch.js +63 -0
- package/dist/node-types/orchestrator-dispatch.js.map +1 -0
- package/dist/node-types/orchestrator-load-state.d.ts +16 -0
- package/dist/node-types/orchestrator-load-state.d.ts.map +1 -0
- package/dist/node-types/orchestrator-load-state.js +60 -0
- package/dist/node-types/orchestrator-load-state.js.map +1 -0
- package/dist/node-types/orchestrator-route.d.ts +16 -0
- package/dist/node-types/orchestrator-route.d.ts.map +1 -0
- package/dist/node-types/orchestrator-route.js +28 -0
- package/dist/node-types/orchestrator-route.js.map +1 -0
- package/dist/node-types/receive-task.d.ts +2 -3
- package/dist/node-types/receive-task.d.ts.map +1 -1
- package/dist/node-types/receive-task.js +3 -48
- package/dist/node-types/receive-task.js.map +1 -1
- package/dist/templates/weaver-template.d.ts +11 -0
- package/dist/templates/weaver-template.d.ts.map +1 -0
- package/dist/templates/weaver-template.js +53 -0
- package/dist/templates/weaver-template.js.map +1 -0
- package/dist/ui/bot-activity.js +2 -2
- package/dist/ui/bot-constants.d.ts +14 -0
- package/dist/ui/bot-constants.d.ts.map +1 -0
- package/dist/ui/bot-constants.js +189 -0
- package/dist/ui/bot-constants.js.map +1 -0
- package/dist/ui/bot-panel.js +207 -245
- package/dist/ui/bot-slot-card.js +141 -0
- package/dist/ui/budget-bar.js +59 -0
- package/dist/ui/chat-task-result.js +178 -0
- package/dist/ui/decision-log.js +136 -0
- package/dist/ui/profile-card.js +158 -0
- package/dist/ui/profile-editor.js +597 -0
- package/dist/ui/swarm-controls.js +245 -0
- package/dist/ui/swarm-dashboard.js +3012 -0
- package/dist/ui/task-create-form.js +98 -0
- package/dist/ui/task-detail-view.js +1044 -0
- package/dist/ui/task-pool-list.js +156 -0
- package/dist/workflows/orchestrator.d.ts +21 -0
- package/dist/workflows/orchestrator.d.ts.map +1 -0
- package/dist/workflows/orchestrator.js +281 -0
- package/dist/workflows/orchestrator.js.map +1 -0
- package/dist/workflows/weaver-bot-session.d.ts +65 -0
- package/dist/workflows/weaver-bot-session.d.ts.map +1 -0
- package/dist/workflows/weaver-bot-session.js +68 -0
- package/dist/workflows/weaver-bot-session.js.map +1 -0
- package/dist/workflows/weaver.d.ts +24 -0
- package/dist/workflows/weaver.d.ts.map +1 -0
- package/dist/workflows/weaver.js +28 -0
- package/dist/workflows/weaver.js.map +1 -0
- package/flowweaver.manifest.json +547 -133
- package/package.json +1 -1
- package/src/ai-chat-provider.ts +378 -371
- package/src/bot/ai-router.ts +132 -0
- package/src/bot/assistant-tools.ts +47 -29
- package/src/bot/async-mutex.ts +37 -0
- package/src/bot/bot-manager.ts +3 -3
- package/src/bot/bot-registry.ts +2 -2
- package/src/bot/conversation-store.ts +2 -1
- package/src/bot/dashboard.ts +17 -8
- package/src/bot/improve-loop.ts +6 -6
- package/src/bot/index.ts +2 -4
- package/src/bot/instance-manager.ts +128 -0
- package/src/bot/orchestrator.ts +244 -0
- package/src/bot/profile-store.ts +225 -0
- package/src/bot/profile-types.ts +141 -0
- package/src/bot/run-store.ts +8 -0
- package/src/bot/runner.ts +9 -1
- package/src/bot/swarm-controller.ts +780 -0
- package/src/bot/swarm-event-log.ts +57 -0
- package/src/bot/task-prompt-builder.ts +309 -0
- package/src/bot/task-store.ts +407 -0
- package/src/bot/task-types.ts +100 -0
- package/src/bot/types.ts +8 -0
- package/src/cli-handlers.ts +78 -53
- package/src/docs/weaver-bot-usage.md +35 -18
- package/src/docs/weaver-config.md +20 -0
- package/src/docs/weaver-task-queue.md +31 -19
- package/src/index.ts +5 -4
- package/src/mcp-tools.ts +129 -372
- package/src/node-types/bot-report.ts +6 -24
- package/src/node-types/orchestrator-dispatch.ts +71 -0
- package/src/node-types/orchestrator-load-state.ts +66 -0
- package/src/node-types/orchestrator-route.ts +33 -0
- package/src/node-types/receive-task.ts +3 -57
- package/src/ui/bot-activity.tsx +2 -2
- package/src/ui/bot-constants.ts +192 -0
- package/src/ui/bot-panel.tsx +213 -247
- package/src/ui/bot-slot-card.tsx +139 -0
- package/src/ui/budget-bar.tsx +30 -0
- package/src/ui/chat-task-result.tsx +236 -0
- package/src/ui/decision-log.tsx +148 -0
- package/src/ui/profile-card.tsx +157 -0
- package/src/ui/profile-editor.tsx +384 -0
- package/src/ui/swarm-controls.tsx +260 -0
- package/src/ui/swarm-dashboard.tsx +647 -0
- package/src/ui/task-create-form.tsx +87 -0
- package/src/ui/task-detail-view.tsx +841 -0
- package/src/ui/task-pool-list.tsx +187 -0
- package/src/workflows/orchestrator.ts +302 -0
- package/dist/docs/weaver-bot-usage.md +0 -34
- package/dist/docs/weaver-genesis.md +0 -32
- package/dist/docs/weaver-task-queue.md +0 -34
- package/dist/ui/bot-workspace.js +0 -1015
- package/dist/ui/chat-bot-result.js +0 -71
- package/dist/ui/queue-input.js +0 -82
- package/dist/ui/session-bar.js +0 -174
- package/src/bot/error-guide.ts +0 -4
- package/src/bot/retry-utils.ts +0 -4
- package/src/bot/session-state.ts +0 -116
- package/src/bot/task-queue.ts +0 -262
- package/src/ui/bot-workspace.tsx +0 -442
- package/src/ui/chat-bot-result.tsx +0 -81
- package/src/ui/queue-input.tsx +0 -56
- package/src/ui/session-bar.tsx +0 -157
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export interface SwarmEvent {
|
|
5
|
+
id: number;
|
|
6
|
+
type: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
data?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Append-only event log for swarm-level events.
|
|
13
|
+
*
|
|
14
|
+
* Writes SwarmEvent objects to `.weaver/swarm-events.ndjson`.
|
|
15
|
+
* The platform tails this file via SSE to stream live dashboard updates.
|
|
16
|
+
* Decoupled from execution: the swarm controller writes, the UI reads, independently.
|
|
17
|
+
*/
|
|
18
|
+
export class SwarmEventLog {
|
|
19
|
+
private readonly filePath: string;
|
|
20
|
+
private nextId = 0;
|
|
21
|
+
|
|
22
|
+
constructor(projectDir: string) {
|
|
23
|
+
const dir = path.join(projectDir, '.weaver');
|
|
24
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
25
|
+
this.filePath = path.join(dir, 'swarm-events.ndjson');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Append a swarm event with auto-assigned sequential ID. */
|
|
29
|
+
emit(event: Omit<SwarmEvent, 'id'>): void {
|
|
30
|
+
const full: SwarmEvent = { ...event, id: this.nextId++ };
|
|
31
|
+
fs.appendFileSync(this.filePath, JSON.stringify(full) + '\n', 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Read events starting from offset (0-based event ID).
|
|
36
|
+
* For repeated polling, pass the last received id + 1 as offset.
|
|
37
|
+
*/
|
|
38
|
+
tail(offset: number): SwarmEvent[] {
|
|
39
|
+
if (!fs.existsSync(this.filePath)) return [];
|
|
40
|
+
const events: SwarmEvent[] = [];
|
|
41
|
+
const lines = fs.readFileSync(this.filePath, 'utf-8').split('\n');
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
if (!line.trim()) continue;
|
|
44
|
+
try {
|
|
45
|
+
const event = JSON.parse(line) as SwarmEvent;
|
|
46
|
+
if (event.id >= offset) events.push(event);
|
|
47
|
+
} catch { /* skip corrupt line */ }
|
|
48
|
+
}
|
|
49
|
+
return events;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Remove the event log file and reset the ID counter. */
|
|
53
|
+
clear(): void {
|
|
54
|
+
try { fs.unlinkSync(this.filePath); } catch { /* ok */ }
|
|
55
|
+
this.nextId = 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build AI prompt from task context with sliding window and 4,000 token cap.
|
|
3
|
+
*
|
|
4
|
+
* Prompt structure:
|
|
5
|
+
* ## Task: {title}
|
|
6
|
+
* {description}
|
|
7
|
+
* ### Notes
|
|
8
|
+
* ### Relevant Files
|
|
9
|
+
* ### Previous Attempts (last 3 full, older condensed)
|
|
10
|
+
* ### Last Error
|
|
11
|
+
* ### Parent Context (title + description + sibling status)
|
|
12
|
+
*
|
|
13
|
+
* Truncation cascade when over budget:
|
|
14
|
+
* 1. Older summaries → one-liners only
|
|
15
|
+
* 2. File list → only files from last 2 runs
|
|
16
|
+
* 3. Parent context → title only
|
|
17
|
+
* 4. Notes → first 500 chars
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { Task, RunSummary } from './task-types.js';
|
|
21
|
+
import type { ProfilePreferences } from './profile-types.js';
|
|
22
|
+
|
|
23
|
+
const MAX_CONTEXT_TOKENS = 4000;
|
|
24
|
+
const CHARS_PER_TOKEN = 4; // rough estimate
|
|
25
|
+
const MAX_CONTEXT_CHARS = MAX_CONTEXT_TOKENS * CHARS_PER_TOKEN;
|
|
26
|
+
const FULL_SUMMARY_COUNT = 3;
|
|
27
|
+
|
|
28
|
+
export function buildTaskPrompt(
|
|
29
|
+
task: Task,
|
|
30
|
+
parentTask?: Task | null,
|
|
31
|
+
siblingTasks?: Task[],
|
|
32
|
+
preferences?: ProfilePreferences,
|
|
33
|
+
): string {
|
|
34
|
+
// Build the full (un-truncated) prompt first
|
|
35
|
+
const prompt = buildFull(task, parentTask, siblingTasks, preferences);
|
|
36
|
+
|
|
37
|
+
if (prompt.length <= MAX_CONTEXT_CHARS) {
|
|
38
|
+
return prompt;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Over budget — apply truncation cascade progressively
|
|
42
|
+
return truncatePrompt(task, parentTask, siblingTasks, preferences);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Full prompt builder (no truncation)
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
function buildFull(
|
|
50
|
+
task: Task,
|
|
51
|
+
parentTask?: Task | null,
|
|
52
|
+
siblingTasks?: Task[],
|
|
53
|
+
preferences?: ProfilePreferences,
|
|
54
|
+
): string {
|
|
55
|
+
const sections: string[] = [];
|
|
56
|
+
|
|
57
|
+
// Always: title + description
|
|
58
|
+
sections.push(`## Task: ${task.title}\n\n${task.description}`);
|
|
59
|
+
|
|
60
|
+
// Notes
|
|
61
|
+
if (task.context.notes) {
|
|
62
|
+
sections.push(`### Notes\n${task.context.notes}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Files
|
|
66
|
+
if (task.context.files.length > 0) {
|
|
67
|
+
sections.push(`### Relevant Files\n${task.context.files.join('\n')}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Run summaries: last 3 in full, older condensed
|
|
71
|
+
const summaries = task.context.runSummaries;
|
|
72
|
+
if (summaries.length > 0) {
|
|
73
|
+
const lines: string[] = [];
|
|
74
|
+
const recentStart = Math.max(0, summaries.length - FULL_SUMMARY_COUNT);
|
|
75
|
+
|
|
76
|
+
// Condensed older summaries
|
|
77
|
+
for (let i = 0; i < recentStart; i++) {
|
|
78
|
+
lines.push(condenseSummary(summaries[i]!));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Full recent summaries
|
|
82
|
+
for (let i = recentStart; i < summaries.length; i++) {
|
|
83
|
+
lines.push(fullSummary(summaries[i]!));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
sections.push(`### Previous Attempts\n${lines.join('\n')}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Last error
|
|
90
|
+
if (task.context.lastError) {
|
|
91
|
+
sections.push(`### Last Error\n${task.context.lastError}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Execution preferences
|
|
95
|
+
if (preferences) {
|
|
96
|
+
sections.push(buildPreferencesSection(preferences));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Parent context
|
|
100
|
+
if (parentTask) {
|
|
101
|
+
sections.push(buildParentSection(parentTask, siblingTasks));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return sections.join('\n\n');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Truncation cascade
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
function truncatePrompt(
|
|
112
|
+
task: Task,
|
|
113
|
+
parentTask?: Task | null,
|
|
114
|
+
siblingTasks?: Task[],
|
|
115
|
+
preferences?: ProfilePreferences,
|
|
116
|
+
): string {
|
|
117
|
+
// Level 1: All summaries condensed to one-liners
|
|
118
|
+
let result = buildWithTruncation(task, parentTask, siblingTasks, {
|
|
119
|
+
allSummariesCondensed: true,
|
|
120
|
+
filesFromRecentRunsOnly: false,
|
|
121
|
+
parentTitleOnly: false,
|
|
122
|
+
notesCapped: false,
|
|
123
|
+
}, preferences);
|
|
124
|
+
if (result.length <= MAX_CONTEXT_CHARS) return result;
|
|
125
|
+
|
|
126
|
+
// Level 2: File list → only files from last 2 runs
|
|
127
|
+
result = buildWithTruncation(task, parentTask, siblingTasks, {
|
|
128
|
+
allSummariesCondensed: true,
|
|
129
|
+
filesFromRecentRunsOnly: true,
|
|
130
|
+
parentTitleOnly: false,
|
|
131
|
+
notesCapped: false,
|
|
132
|
+
}, preferences);
|
|
133
|
+
if (result.length <= MAX_CONTEXT_CHARS) return result;
|
|
134
|
+
|
|
135
|
+
// Level 3: Parent context → title only
|
|
136
|
+
result = buildWithTruncation(task, parentTask, siblingTasks, {
|
|
137
|
+
allSummariesCondensed: true,
|
|
138
|
+
filesFromRecentRunsOnly: true,
|
|
139
|
+
parentTitleOnly: true,
|
|
140
|
+
notesCapped: false,
|
|
141
|
+
}, preferences);
|
|
142
|
+
if (result.length <= MAX_CONTEXT_CHARS) return result;
|
|
143
|
+
|
|
144
|
+
// Level 4: Notes → first 500 chars
|
|
145
|
+
result = buildWithTruncation(task, parentTask, siblingTasks, {
|
|
146
|
+
allSummariesCondensed: true,
|
|
147
|
+
filesFromRecentRunsOnly: true,
|
|
148
|
+
parentTitleOnly: true,
|
|
149
|
+
notesCapped: true,
|
|
150
|
+
}, preferences);
|
|
151
|
+
|
|
152
|
+
// Hard-truncate if still over (shouldn't happen with reasonable data)
|
|
153
|
+
if (result.length > MAX_CONTEXT_CHARS) {
|
|
154
|
+
return result.slice(0, MAX_CONTEXT_CHARS);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface TruncationFlags {
|
|
161
|
+
allSummariesCondensed: boolean;
|
|
162
|
+
filesFromRecentRunsOnly: boolean;
|
|
163
|
+
parentTitleOnly: boolean;
|
|
164
|
+
notesCapped: boolean;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function buildWithTruncation(
|
|
168
|
+
task: Task,
|
|
169
|
+
parentTask: Task | null | undefined,
|
|
170
|
+
siblingTasks: Task[] | undefined,
|
|
171
|
+
flags: TruncationFlags,
|
|
172
|
+
preferences?: ProfilePreferences,
|
|
173
|
+
): string {
|
|
174
|
+
const sections: string[] = [];
|
|
175
|
+
|
|
176
|
+
// Always: title + description
|
|
177
|
+
sections.push(`## Task: ${task.title}\n\n${task.description}`);
|
|
178
|
+
|
|
179
|
+
// Notes (potentially capped)
|
|
180
|
+
if (task.context.notes) {
|
|
181
|
+
const notes =
|
|
182
|
+
flags.notesCapped && task.context.notes.length > 500
|
|
183
|
+
? task.context.notes.slice(0, 500) + '...'
|
|
184
|
+
: task.context.notes;
|
|
185
|
+
sections.push(`### Notes\n${notes}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Files (potentially only from recent runs)
|
|
189
|
+
if (flags.filesFromRecentRunsOnly) {
|
|
190
|
+
const recentFiles = new Set<string>();
|
|
191
|
+
for (const s of task.context.runSummaries.slice(-2)) {
|
|
192
|
+
for (const f of s.filesModified) recentFiles.add(f);
|
|
193
|
+
}
|
|
194
|
+
if (recentFiles.size > 0) {
|
|
195
|
+
sections.push(`### Relevant Files\n${[...recentFiles].join('\n')}`);
|
|
196
|
+
}
|
|
197
|
+
} else if (task.context.files.length > 0) {
|
|
198
|
+
sections.push(`### Relevant Files\n${task.context.files.join('\n')}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// All summaries condensed
|
|
202
|
+
if (task.context.runSummaries.length > 0) {
|
|
203
|
+
if (flags.allSummariesCondensed) {
|
|
204
|
+
const lines = task.context.runSummaries.map((s) => condenseSummary(s));
|
|
205
|
+
sections.push(`### Previous Attempts\n${lines.join('\n')}`);
|
|
206
|
+
} else {
|
|
207
|
+
// This path isn't used in truncation, but included for completeness
|
|
208
|
+
const lines: string[] = [];
|
|
209
|
+
const recentStart = Math.max(0, task.context.runSummaries.length - FULL_SUMMARY_COUNT);
|
|
210
|
+
for (let i = 0; i < recentStart; i++) {
|
|
211
|
+
lines.push(condenseSummary(task.context.runSummaries[i]!));
|
|
212
|
+
}
|
|
213
|
+
for (let i = recentStart; i < task.context.runSummaries.length; i++) {
|
|
214
|
+
lines.push(fullSummary(task.context.runSummaries[i]!));
|
|
215
|
+
}
|
|
216
|
+
sections.push(`### Previous Attempts\n${lines.join('\n')}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Last error (truncated in aggressive mode)
|
|
221
|
+
if (task.context.lastError) {
|
|
222
|
+
const errorText = flags.notesCapped
|
|
223
|
+
? task.context.lastError.slice(0, 300)
|
|
224
|
+
: task.context.lastError;
|
|
225
|
+
sections.push(`### Last Error\n${errorText}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Execution preferences
|
|
229
|
+
if (preferences) {
|
|
230
|
+
sections.push(buildPreferencesSection(preferences));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Parent context
|
|
234
|
+
if (parentTask) {
|
|
235
|
+
if (flags.parentTitleOnly) {
|
|
236
|
+
sections.push(`### Parent Context\nPart of: "${parentTask.title}"`);
|
|
237
|
+
} else {
|
|
238
|
+
sections.push(buildParentSection(parentTask, siblingTasks));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return sections.join('\n\n');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
// Formatting helpers
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
function condenseSummary(s: RunSummary): string {
|
|
250
|
+
return `- Run ${s.runId.slice(0, 8)} (${s.botId}): ${s.outcome} — ${s.summary.slice(0, 80)} (${Math.round(s.durationMs / 1000)}s, ${s.tokensUsed} tok)`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function fullSummary(s: RunSummary): string {
|
|
254
|
+
const lines: string[] = [];
|
|
255
|
+
lines.push(`\n**Run ${s.runId.slice(0, 8)} (${s.botId}) — ${s.outcome}**`);
|
|
256
|
+
lines.push(s.summary);
|
|
257
|
+
if (s.filesModified.length > 0) lines.push(`Files: ${s.filesModified.join(', ')}`);
|
|
258
|
+
if (s.error) lines.push(`Error: ${s.error}`);
|
|
259
|
+
lines.push(
|
|
260
|
+
`Duration: ${Math.round(s.durationMs / 1000)}s · Tokens: ${s.tokensUsed} · Cost: $${s.cost.toFixed(3)}`,
|
|
261
|
+
);
|
|
262
|
+
return lines.join('\n');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function buildParentSection(
|
|
266
|
+
parentTask: Task,
|
|
267
|
+
siblingTasks?: Task[],
|
|
268
|
+
): string {
|
|
269
|
+
let section = `### Parent Context\nPart of: "${parentTask.title}" — ${parentTask.description}`;
|
|
270
|
+
if (siblingTasks && siblingTasks.length > 0) {
|
|
271
|
+
const siblingLines = siblingTasks
|
|
272
|
+
.map(
|
|
273
|
+
(s) =>
|
|
274
|
+
`- ${statusIcon(s.status)} ${s.title} (${s.status})`,
|
|
275
|
+
)
|
|
276
|
+
.join('\n');
|
|
277
|
+
section += `\n\nSibling tasks:\n${siblingLines}`;
|
|
278
|
+
}
|
|
279
|
+
return section;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function buildPreferencesSection(preferences: ProfilePreferences): string {
|
|
283
|
+
const lines = ['## Execution Preferences'];
|
|
284
|
+
lines.push(`Cost strategy: ${preferences.costStrategy}`);
|
|
285
|
+
if (preferences.maxCostPerRun !== undefined) {
|
|
286
|
+
lines.push(`Max cost per run: $${preferences.maxCostPerRun.toFixed(2)}`);
|
|
287
|
+
}
|
|
288
|
+
if (preferences.maxCostPerTask !== undefined) {
|
|
289
|
+
lines.push(`Max cost per task: $${preferences.maxCostPerTask.toFixed(2)}`);
|
|
290
|
+
}
|
|
291
|
+
if (preferences.instructions) {
|
|
292
|
+
lines.push(`Instructions: ${preferences.instructions}`);
|
|
293
|
+
}
|
|
294
|
+
lines.push(`Approval required: ${preferences.requireApproval ? 'yes' : 'no'}`);
|
|
295
|
+
return lines.join('\n');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function statusIcon(status: string): string {
|
|
299
|
+
switch (status) {
|
|
300
|
+
case 'done':
|
|
301
|
+
return '\u2705';
|
|
302
|
+
case 'failed':
|
|
303
|
+
return '\u274C';
|
|
304
|
+
case 'in-progress':
|
|
305
|
+
return '\u25CF';
|
|
306
|
+
default:
|
|
307
|
+
return '\u25CB';
|
|
308
|
+
}
|
|
309
|
+
}
|