Skip to content
Open
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
126 changes: 113 additions & 13 deletions src/evolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,99 @@ function shouldSkipHubCalls(signals) {
return true;
}

// Read file head (first maxBytes) to extract initial user prompt
function readFileHead(filePath, maxBytes = 8192) {
try {
if (!fs.existsSync(filePath)) return '';
const fd = fs.openSync(filePath, 'r');
const buffer = Buffer.alloc(maxBytes);
const bytesRead = fs.readSync(fd, buffer, 0, maxBytes, 0);
fs.closeSync(fd);
return buffer.slice(0, bytesRead).toString('utf8');
} catch (e) {
console.warn(`[readFileHead] Failed to read ${filePath}: ${e.message}`);
return '';
}
}

// Extract first USER message from session content
function extractFirstUserMessage(content) {
if (!content) return null;
const lines = content.split('\n');
for (const line of lines) {
if (!line.trim()) continue;
try {
const data = JSON.parse(line);
const msg = data.message || data;
if (msg.role === 'user' || msg.role === 'USER') {
const msgContent = msg.content;
if (Array.isArray(msgContent)) {
// Handle array content (e.g., from Claude/OpenAI)
const textParts = msgContent.filter(c => c.type === 'text').map(c => c.text).join('');
return textParts.trim();
} else if (typeof msgContent === 'string') {
return msgContent.trim();
}
}
} catch (e) {
// Not JSON, skip
}
}
return null;
}

// Unified entry to get current session's initial user prompt
function getCurrentSessionInitialPrompt() {
const sessionSource = SESSION_SOURCE;

function getCursorPrompt() {
if (!CURSOR_TRANSCRIPTS_DIR) return null;
try {
const files = collectTranscriptFiles(CURSOR_TRANSCRIPTS_DIR, 3);
if (!files || files.length === 0) return null;
files.sort((a, b) => b.time - a.time);
const headContent = readFileHead(files[0].path, 16384);
return extractFirstUserMessage(headContent);
} catch (e) {
console.warn(`[getCurrentSessionInitialPrompt] Failed to collect cursor transcripts: ${e.message}`);
return null;
}
}

function getOpenClawPrompt() {
try {
const sessions = fs.readdirSync(AGENT_SESSIONS_DIR)
.filter(f => f.endsWith('.jsonl'))
.map(f => ({
path: path.join(AGENT_SESSIONS_DIR, f),
time: fs.statSync(path.join(AGENT_SESSIONS_DIR, f)).mtime.getTime(),
}))
.sort((a, b) => b.time - a.time);
if (!sessions || sessions.length === 0) return null;
const headContent = readFileHead(sessions[0].path, 16384);
return extractFirstUserMessage(headContent);
} catch (e) {
console.warn(`[getCurrentSessionInitialPrompt] Failed to read agent sessions: ${e.message}`);
return null;
}
}

if (sessionSource === 'cursor') {
return getCursorPrompt();
}

if (sessionSource === 'openclaw') {
return getOpenClawPrompt();
}

if (sessionSource === 'merge') {
return getOpenClawPrompt() || getCursorPrompt();
}

// 'auto' (default): OpenClaw primary, Cursor fallback
return getOpenClawPrompt() || getCursorPrompt();
}

// Load environment variables from repo root
try {
require('dotenv').config({ path: path.join(REPO_ROOT, '.env'), quiet: true });
Expand Down Expand Up @@ -1130,6 +1223,7 @@ async function run() {

const cycleNum = getNextCycleId();
const cycleId = `Cycle #${cycleNum}`;
const initialUserPrompt = getCurrentSessionInitialPrompt();

// 2. Detect Workspace State & Local Overrides
// Logic: Default to generic reporting (message)
Expand Down Expand Up @@ -1479,30 +1573,30 @@ async function run() {
const hubEvents = consumeHubEvents();
if (hubEvents.length > 0) {
const HUB_EVENT_SIGNALS = {
// ── 对话 ──────────────────────────────────────────────────────
// ── Dialog ──────────────────────────────────────────────────────
dialog_message: ['dialog', 'respond_required'],

// ── 议会 / 治理 ───────────────────────────────────────────────
// ── Council / Governance ─────────────────────────────────────────
council_invite: ['council', 'governance', 'respond_required'],
council_second_request: ['council', 'governance', 'second_request', 'respond_required'],
council_vote: ['council', 'vote', 'governance', 'respond_required'],
council_community_vote: ['council', 'community_vote', 'governance', 'respond_required'],
council_decision: ['council', 'decision', 'governance'],
council_decision_notification: ['council', 'governance'],

// ── 审议 / 辩论 ───────────────────────────────────────────────
// ── Deliberation / Debate ───────────────────────────────────────
deliberation_invite: ['deliberation', 'governance', 'respond_required'],
deliberation_challenge: ['deliberation', 'challenge', 'respond_required'],
deliberation_next_round: ['deliberation', 'next_round', 'respond_required'],
deliberation_completed: ['deliberation', 'governance'],

// ── 协作 / 会话 ───────────────────────────────────────────────
// ── Collaboration / Session ──────────────────────────────────────
collaboration_invite: ['collaboration', 'respond_required'],
session_message: ['collaboration', 'dialog', 'respond_required'],
session_nudge: ['collaboration', 'idle_warning'],
task_board_update: ['collaboration', 'task_update'],

// ── 任务 / 工作池 ─────────────────────────────────────────────
// ── Task / Work Pool ───────────────────────────────────────────
task_available: ['task', 'work_available'],
work_assigned: ['task', 'work_assigned'],
swarm_subtask_available: ['swarm', 'task', 'work_available'],
Expand All @@ -1511,7 +1605,7 @@ async function run() {
pipeline_step_assigned: ['pipeline', 'task', 'work_assigned'],
organism_work: ['organism', 'task', 'work_assigned'],

// ── 蜂群 PDRI 角色事件 ──────────────────────────────────────
// ── Swarm PDRI Role Events ──────────────────────────────────────
swarm_plan_available: ['swarm', 'planner', 'work_available'],
swarm_build_available: ['swarm', 'builder', 'work_available'],
swarm_review_available: ['swarm', 'reviewer', 'work_available', 'respond_required'],
Expand All @@ -1521,22 +1615,22 @@ async function run() {
team_formed: ['swarm', 'team', 'collaboration'],
team_dissolved: ['swarm', 'team'],

// ── 隐私计算 ────────────────────────────────────────────────
// ── Privacy Computation ─────────────────────────────────────────
privacy_task_ready: ['privacy', 'sealed_tool', 'work_available'],
privacy_result_available: ['privacy', 'result'],

// ── 评审 / 赏金 ───────────────────────────────────────────────
// ── Review / Bounty ─────────────────────────────────────────────
bounty_review_requested: ['review', 'bounty', 'respond_required'],
peer_review_request: ['review', 'swarm', 'respond_required'],
supplement_request: ['supplement', 'respond_required'],

// ── 成长 / 知识 ───────────────────────────────────────────────
// ── Growth / Knowledge ──────────────────────────────────────────
evolution_circle_formed: ['evolution_circle', 'collaboration'],
knowledge_update: ['knowledge'],
topic_notification: ['topic', 'knowledge'],
reflection_prompt: ['reflection'],

// ── 系统 ──────────────────────────────────────────────────────
// ── System ──────────────────────────────────────────────────────
task_overdue: ['overdue_task', 'urgent'],
};
for (const ev of hubEvents) {
Expand Down Expand Up @@ -1908,6 +2002,8 @@ async function run() {
lines: Number.isFinite(maxFiles) && maxFiles > 0 ? Math.round(maxFiles * 80) : 0,
};

const initialUserPrompt = getCurrentSessionInitialPrompt();

// Merge into existing state to preserve last_solidify (do not wipe it).
const prevState = readStateForSolidify();
prevState.last_run = {
Expand Down Expand Up @@ -1944,6 +2040,7 @@ async function run() {
commitment_deadline: activeTask ? (activeTask._commitment_deadline || null) : null,
applied_lessons: hubLessons.map(function(l) { return l.lesson_id; }).filter(Boolean),
hub_lessons: hubLessons,
initial_user_prompt: initialUserPrompt,
};
writeStateForSolidify(prevState);

Expand Down Expand Up @@ -1977,9 +2074,7 @@ async function run() {
const genesPreview = `\`\`\`json\n${JSON.stringify(genes.slice(0, 6), null, 2)}\n\`\`\``;
const capsulesPreview = `\`\`\`json\n${JSON.stringify(capsules.slice(-3), null, 2)}\n\`\`\``;

const reviewNote = IS_REVIEW_MODE
? 'Review mode: before significant edits, pause and ask the user for confirmation.'
: 'Review mode: disabled.';


// Build recent evolution history summary for context injection
const recentHistorySummary = (() => {
Expand All @@ -1996,6 +2091,9 @@ async function run() {
})();

const context = `
Initial User Prompt (Original Intent):
${initialUserPrompt ? `\`\`\`\n${initialUserPrompt}\n\`\`\`` : '(not available)'}

Runtime state:
- System health: ${healthReport}
- Agent state: ${moodStatus}
Expand Down Expand Up @@ -2085,6 +2183,7 @@ ${mutationDirective}
strategyPolicy,
failedCapsules: recentFailedCapsules,
hubLessons,
initialUserPrompt,
});

// Optional: emit a compact thought process block for wrappers (noise-controlled).
Expand Down Expand Up @@ -2130,6 +2229,7 @@ ${mutationDirective}
dry_run: IS_DRY_RUN,
mutation_id: mutation && mutation.id ? mutation.id : null,
personality_key: personalitySelection && personalitySelection.personality_key ? personalitySelection.personality_key : null,
initial_user_prompt: initialUserPrompt,
},
});
} catch (e) {
Expand Down
2 changes: 2 additions & 0 deletions src/gep/prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ function buildGepPrompt({
failedCapsules,
hubLessons,
strategyPolicy,
initialUserPrompt,
}) {
const parentValue = parentEventId ? `"${parentEventId}"` : 'null';
const selectedGeneId = selectedGene && selectedGene.id ? selectedGene.id : 'gene_<name>';
Expand Down Expand Up @@ -569,6 +570,7 @@ ${buildAntiPatternZone(failedCapsules, signals)}${buildLessonsBlock(hubLessons,
${historyBlock}
${buildNarrativeBlock()}
${buildPrinciplesBlock()}
${initialUserPrompt ? `Context [Initial User Prompt]:\n${initialUserPrompt}\n` : ''}
Context [Execution]:
${executionContext}

Expand Down