/**
 * Pi-SDK - Agent Session for Document Processing
 * Part of OpenClaw dual-layer architecture
 */
import * as fs from 'fs/promises';
import * as fsSync from 'fs';
import * as os from 'os';
import * as path from 'path';
import { documentReader } from '../documents/reader.js';
import { getMinimax } from '../constraints/index.js';
import { p2pNetwork } from '../network/p2p.js';
import { ConstraintLayer } from './constraint-layer.js';
import { WorkflowEngine } from './workflow-engine.js';
import { DeepThinkingEngine, AgentCoordinator } from '@bolloon/constraint-runtime';
import { WorkflowPivotLoop, createDefaultPivotConfig } from './workflow-pivot-loop.js';
import { p2pDocumentTools, initDocumentReceiver } from './p2p-document-tools.js';
import { shellExec } from './shell-tool.js';
import { getBranchPrefix, getCooldownMs } from './shell-guard.js';
import { DiscoveredAgentsManager, createSocialHeartbeat } from '../social/heartbeat.js';
import { getGlobalSharedContext } from '../social/global-shared-context.js';
import { Session, SkillRegistry, saveSession, loadSession } from '@bolloon/constraint-runtime';
import { loadSkillsFromPaths, defaultSkillPaths, describeSkill } from './skill-loader.js';
const SHARED_SESSION_PATH = path.join(process.env.HOME || '/tmp', '.bolloon', 'sessions');
const PERSONA_PATH = path.join(process.env.HOME || '/tmp', '.bolloon', 'persona.json');
export class PiSessionManager {
    session;
    state;
    memory;
    persona = null;
    channels = new Map();
    channelsPath;
    initialized = false;
    sessionDir;
    cwd;
    sharedContext;
    agentId;
    constructor(agentId, cwd) {
        this.cwd = cwd;
        this.sessionDir = path.join(cwd, '.port_sessions');
        this.agentId = agentId;
        const sessionId = `pi-session-${Date.now()}`;
        this.session = new Session(sessionId);
        this.state = {
            id: sessionId,
            agentId,
            cwd,
            startedAt: new Date().toISOString(),
            lastActive: new Date().toISOString()
        };
        this.memory = {
            workingMemory: [],
            summarizedMemory: [],
            fileContext: new Map()
        };
        this.channelsPath = path.join(SHARED_SESSION_PATH, 'pi-channels.json');
        this.sharedContext = getGlobalSharedContext();
    }
    get sessionId() {
        return this.session.sessionId;
    }
    get turnCount() {
        return this.session.turnCount;
    }
    addSessionMessage(msg) {
        this.session.addMessage(msg);
        this.persistSession();
    }
    getSessionHistory() {
        return this.session.history;
    }
    setSessionContext(key, value) {
        this.session.setContext(key, value);
        this.persistSession();
    }
    getSessionContext(key) {
        return this.session.getContext(key);
    }
    persistSession() {
        try {
            const stored = {
                sessionId: this.session.sessionId,
                messages: this.session.history,
                inputTokens: 0,
                outputTokens: 0
            };
            saveSession(stored);
        }
        catch (e) {
            console.warn('Failed to persist session:', e);
        }
    }
    loadPersistedSession() {
        try {
            const sessionId = this.state.id;
            const stored = loadSession(sessionId);
            for (const msg of stored.messages) {
                this.session.addMessage(msg);
            }
        }
        catch {
            // No persisted session found, start fresh
        }
    }
    async initialize() {
        if (this.initialized)
            return;
        await fs.mkdir(SHARED_SESSION_PATH, { recursive: true });
        await fs.mkdir(this.sessionDir, { recursive: true });
        this.persona = await this.loadPersona();
        await this.loadChannels();
        this.loadPersistedSession();
        await this.sharedContext.initialize();
        await this.sharedContext.registerAgent({
            agentId: this.agentId,
            sessionId: this.sessionId,
            channelId: 'system',
            capabilities: this.persona?.capabilities || [],
            status: 'active',
            name: this.persona?.name,
            persona: this.persona ? {
                name: this.persona.name,
                description: this.persona.description,
                capabilities: this.persona.capabilities
            } : undefined
        });
        this.initialized = true;
    }
    async loadPersona() {
        try {
            const data = await fs.readFile(PERSONA_PATH, 'utf-8');
            return JSON.parse(data);
        }
        catch {
            return null;
        }
    }
    async loadChannels() {
        try {
            const data = await fs.readFile(this.channelsPath, 'utf-8');
            const channelsArray = JSON.parse(data);
            this.channels.clear();
            for (const channel of channelsArray) {
                this.channels.set(channel.id, channel);
            }
        }
        catch {
            this.channels.clear();
        }
    }
    async saveChannels() {
        const channelsArray = Array.from(this.channels.values());
        await fs.writeFile(this.channelsPath, JSON.stringify(channelsArray, null, 2));
    }
    async savePersona(persona) {
        await fs.writeFile(PERSONA_PATH, JSON.stringify(persona, null, 2));
        this.persona = persona;
    }
    getPersona() {
        return this.persona;
    }
    getState() {
        return { ...this.state, lastActive: new Date().toISOString() };
    }
    getMemory() {
        return this.memory;
    }
    addToWorkingMemory(content) {
        this.memory.workingMemory.push(content);
        if (this.memory.workingMemory.length > 100) {
            this.memory.workingMemory = this.memory.workingMemory.slice(-100);
        }
        this.state.lastActive = new Date().toISOString();
    }
    addSummarizedMemory(content) {
        this.memory.summarizedMemory.push(content);
        if (this.memory.summarizedMemory.length > 50) {
            this.memory.summarizedMemory = this.memory.summarizedMemory.slice(-50);
        }
    }
    addFileContext(filePath, content) {
        this.memory.fileContext.set(filePath, content);
        if (this.memory.fileContext.size > 20) {
            const entries = Array.from(this.memory.fileContext.entries());
            this.memory.fileContext = new Map(entries.slice(-20));
        }
    }
    updateTokenUsage(promptTokens, completionTokens) {
        this.state.tokenUsage = {
            promptTokens: (this.state.tokenUsage?.promptTokens || 0) + promptTokens,
            completionTokens: (this.state.tokenUsage?.completionTokens || 0) + completionTokens,
            totalTokens: (this.state.tokenUsage?.totalTokens || 0) + promptTokens + completionTokens
        };
    }
    async addMessage(channelId, message) {
        await this.initialize();
        if (!this.channels.has(channelId)) {
            this.channels.set(channelId, {
                id: channelId,
                name: channelId,
                messages: [],
                createdAt: new Date().toISOString(),
                updatedAt: new Date().toISOString()
            });
        }
        const channel = this.channels.get(channelId);
        channel.messages.push(message);
        channel.updatedAt = new Date().toISOString();
        await this.saveChannels();
    }
    async getChannelMessages(channelId) {
        await this.initialize();
        return this.channels.get(channelId)?.messages || [];
    }
    async createChannel(name, peerInfo, persona) {
        await this.initialize();
        const channelId = `ch_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
        const channel = {
            id: channelId,
            name,
            messages: [],
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            ...peerInfo,
            persona: persona || undefined
        };
        this.channels.set(channelId, channel);
        await this.saveChannels();
        return channel;
    }
    async getOrCreatePeerChannel(peerDid, peerName, persona) {
        await this.initialize();
        for (const channel of this.channels.values()) {
            if (channel.peerDid === peerDid) {
                return channel;
            }
        }
        return this.createChannel(`与 ${peerName} 的对话`, {
            peerDid,
            peerName
        }, persona);
    }
    async setChannelInfo(channelId, info) {
        await this.initialize();
        const channel = this.channels.get(channelId);
        if (channel) {
            Object.assign(channel, info, { updatedAt: new Date().toISOString() });
            await this.saveChannels();
        }
    }
    getAllChannels() {
        return Array.from(this.channels.values());
    }
    getChannelPersona(channelId) {
        return this.channels.get(channelId)?.persona;
    }
    async setChannelPersona(channelId, persona) {
        await this.initialize();
        const channel = this.channels.get(channelId);
        if (channel) {
            channel.persona = persona;
            channel.updatedAt = new Date().toISOString();
            await this.saveChannels();
        }
    }
    async addUserActionToSharedContext(content, importance) {
        await this.initialize();
        await this.sharedContext.addUserAction(content, this.agentId, undefined, importance);
        await this.sharedContext.updateAgentStatus(this.agentId, 'active');
    }
    async addSharedKnowledge(knowledge) {
        await this.initialize();
        await this.sharedContext.addSharedKnowledge(knowledge);
    }
    async getRecentActionsSummary(count) {
        return this.sharedContext.getRecentActionsSummary(count);
    }
    async getSharedKnowledge() {
        return this.sharedContext.getSharedKnowledge();
    }
    async getGlobalContext() {
        return this.sharedContext.getFullContext();
    }
    async getGlobalContextSummary() {
        return this.sharedContext.getContextSummary();
    }
    async createCooperation(type, task, toAgentId, context) {
        await this.initialize();
        return this.sharedContext.createCooperation(type, this.agentId, task, toAgentId, context);
    }
    async getPendingCooperations() {
        return this.sharedContext.getPendingCooperations(this.agentId);
    }
    async updateCooperationStatus(cooperationId, status, result) {
        await this.sharedContext.updateCooperationStatus(cooperationId, status, result);
    }
    async getAllRegisteredAgents() {
        return this.sharedContext.getAllAgents();
    }
    async findAgentByCapability(capability) {
        return this.sharedContext.findAgentByCapability(capability);
    }
    async getCooperation(cooperationId) {
        return this.sharedContext.getCooperation(cooperationId);
    }
    async updateAgentStatusInRegistry(status) {
        await this.sharedContext.updateAgentStatus(this.agentId, status);
    }
}
const TOOL_DEFINITIONS = `
可用工具:
1. read_document(path) - 读取文档内容，支持 .txt, .md, .pdf, .docx
2. summarize_document(path, context?) - 总结文档内容，可选提供上下文
3. improve_document(path, requirements) - 改进文档，需提供文件路径和改进要求
4. list_peers() - 列出已连接的对等节点
5. send_message(peer_id, message) - 向指定对等节点发送消息
6. broadcast_message(message) - 向所有对等节点广播消息
7. get_identity() - 获取当前智能体身份信息
8. set_persona(persona_json) - 更新智能体 persona，包含 name、description、personality、greeting 等
9. run_workflow(steps) - 执行预定义工作流
10. get_operation_logs() - 获取操作日志
`;
class PiAgentSession {
    cwd;
    peerId;
    identity;
    persona = null;
    minimaxAvailable = false;
    workflows = new Map();
    constraintLayer;
    workflowEngine;
    sessionManager;
    agentsManager;
    socialHeartbeat = null;
    messageHistory = [];
    tools = new Map();
    skillRegistry = new SkillRegistry();
    MAX_REACT_ITERATIONS = 100;
    MAX_REFINE_ATTEMPTS = 3;
    QUALITY_THRESHOLD = 0.6;
    thinkingEngine = new DeepThinkingEngine(3);
    coordinator = new AgentCoordinator(3);
    harness = null;
    harnessEnabled = false;
    usePivotLoop = false;
    pivotLoopConfig;
    constructor(config) {
        this.cwd = config.cwd;
        this.peerId = config.peerId || 'local';
        this.identity = config.identityDoc || this.createDefaultIdentity();
        this.minimaxAvailable = this.checkMinimax();
        this.constraintLayer = new ConstraintLayer();
        this.workflowEngine = new WorkflowEngine(this.constraintLayer);
        this.sessionManager = new PiSessionManager(this.identity.did, this.cwd);
        this.agentsManager = new DiscoveredAgentsManager();
        this.usePivotLoop = config.usePivotLoop ?? false;
        this.pivotLoopConfig = config.pivotLoopConfig;
        this.initSession();
        initDocumentReceiver();
        this.registerTools();
        this.loadSkills(config.skillsPaths);
        this.initHarness();
    }
    /**
     * 从 SKILL.md 目录加载 skills 进 skillRegistry.
     *
     * 路径解析优先级 (后者覆盖前者同名 skill):
     *   1. 显式传入的 skillsPaths
     *   2. ~/.bolloon/skills/         全局用户级
     *   3. <cwd>/.bolloon/skills/     项目级
     *   4. ~/.boll/skills/            全局 (兼容 bollharness 旧用户)
     *   5. <bolloon-repo>/src/bollharness/.boll/skills/  bolloon 仓库内置 skill
     *      (bolloon 项目本身用 pi-sdk 写核心, 这 19 个 skill 视为项目级 builtin)
     *
     * 静默忽略不存在的目录.
     */
    loadSkills(paths) {
        let resolved;
        if (paths && paths.length > 0) {
            resolved = paths;
        }
        else {
            resolved = [
                ...defaultSkillPaths(os.homedir(), this.cwd),
                // bolloon 仓库内置 skill (相对本 npm 包的位置)
                this.findBolloonBuiltinSkillsPath(),
            ].filter((p) => Boolean(p));
        }
        loadSkillsFromPaths(resolved)
            .then((skills) => {
            for (const s of skills) {
                if (this.skillRegistry.has(s.name)) {
                    this.skillRegistry.unregister(s.name);
                }
                this.skillRegistry.register(s);
            }
            console.log(`[loadSkills] 已加载 ${skills.length} 个 skill: ${skills.map(describeSkill).join(' | ')}`);
        })
            .catch((err) => {
            console.error('[loadSkills] 加载失败:', err);
        });
    }
    /**
     * 定位 bolloon 仓库内置的 bollharness skill 目录.
     * 向上回溯 cwd, 找第一个包含 src/bollharness/.boll/skills 的祖先.
     * 找不到时返回 null (例如把 bolloon-agent 作为外部依赖安装时).
     */
    findBolloonBuiltinSkillsPath() {
        let dir = this.cwd;
        for (let i = 0; i < 6; i++) {
            const candidate = path.join(dir, 'src', 'bollharness', '.boll', 'skills');
            try {
                if (fsSync.existsSync(candidate) && fsSync.statSync(candidate).isDirectory()) {
                    return candidate;
                }
            }
            catch {
                // 忽略 stat 异常, 继续向上
            }
            const parent = path.dirname(dir);
            if (parent === dir)
                break;
            dir = parent;
        }
        return null;
    }
    async initHarness() {
        try {
            const { createBollharnessIntegration } = await import('../bollharness-integration/index.js');
            this.harness = createBollharnessIntegration();
            this.harnessEnabled = true;
        }
        catch (e) {
            console.warn('[PiAgentSession] Harness initialization failed:', e);
            this.harnessEnabled = false;
        }
    }
    registerTools() {
        this.tools.set('read_document', {
            name: 'read_document',
            description: '读取文档内容，支持 .txt, .md, .pdf, .docx 格式',
            parameters: { path: '文件路径' },
            execute: async (args) => {
                try {
                    const content = await documentReader.read(args.path);
                    return {
                        success: true,
                        output: `📄 ${content.metadata.filename}\n大小: ${content.metadata.size} 字节\n\n${content.text.substring(0, 1000)}${content.text.length > 1000 ? '...' : ''}`
                    };
                }
                catch (e) {
                    return { success: false, error: String(e) };
                }
            }
        });
        this.tools.set('summarize_document', {
            name: 'summarize_document',
            description: '总结文档内容，分析并生成摘要',
            parameters: { path: '文件路径', context: '可选上下文信息' },
            execute: async (args) => {
                try {
                    if (!this.minimaxAvailable) {
                        return { success: false, error: 'LLM未初始化，请设置 MINIMAX_API_KEY' };
                    }
                    const result = await this.summarizeDocument(args.path, args.context);
                    return {
                        success: true,
                        output: `📝 摘要:\n${result.summary}\n\n质量评分: ${(result.qualityScore * 10).toFixed(1)}/10`
                    };
                }
                catch (e) {
                    return { success: false, error: String(e) };
                }
            }
        });
        this.tools.set('improve_document', {
            name: 'improve_document',
            description: '根据要求改进文档内容',
            parameters: { path: '文件路径', requirements: '改进要求' },
            execute: async (args) => {
                try {
                    if (!this.minimaxAvailable) {
                        return { success: false, error: 'LLM未初始化，请设置 MINIMAX_API_KEY' };
                    }
                    const result = await this.improveDocument({
                        originalPath: args.path,
                        requirements: args.requirements
                    });
                    return {
                        success: true,
                        output: `✅ 改进${result.improved ? '成功' : '失败'}\n质量评分: ${(result.qualityScore * 10).toFixed(1)}/10\n${result.newContent ? '\n改进内容:\n' + result.newContent.substring(0, 500) + '...' : ''}`
                    };
                }
                catch (e) {
                    return { success: false, error: String(e) };
                }
            }
        });
        this.tools.set('list_peers', {
            name: 'list_peers',
            description: '列出已连接的对等节点',
            parameters: {},
            execute: async () => {
                const peers = p2pNetwork.getPeers();
                if (peers.length === 0) {
                    return { success: true, output: '当前无连接的对等节点' };
                }
                return { success: true, output: `已连接节点 (${peers.length}):\n${peers.map(p => `  - ${p}`).join('\n')}` };
            }
        });
        this.tools.set('send_message', {
            name: 'send_message',
            description: '向指定对等节点发送消息',
            parameters: { peer_id: '对等节点ID', message: '消息内容' },
            execute: async (args) => {
                try {
                    await p2pNetwork.sendMessage(args.peer_id, 'message', args.message);
                    return { success: true, output: `消息已发送到 ${args.peer_id}` };
                }
                catch (e) {
                    return { success: false, error: String(e) };
                }
            }
        });
        this.tools.set('broadcast_message', {
            name: 'broadcast_message',
            description: '向所有对等节点广播消息',
            parameters: { message: '消息内容' },
            execute: async (args) => {
                try {
                    await p2pNetwork.broadcast('message', args.message);
                    return { success: true, output: '消息已广播到所有节点' };
                }
                catch (e) {
                    return { success: false, error: String(e) };
                }
            }
        });
        this.tools.set('get_identity', {
            name: 'get_identity',
            description: '获取当前智能体身份信息',
            parameters: {},
            execute: async () => {
                const id = this.getIdentity();
                const extraInfo = id.cid ? `\nCID: ${id.cid}` : '';
                const ipnsInfo = id.ipnsName ? `\nIPNS: ${id.ipnsName}` : '';
                return {
                    success: true,
                    output: `DID: ${id.did}\n名称: ${id.name}\n公钥: ${id.publicKey}${extraInfo}${ipnsInfo}\n创建时间: ${new Date(id.createdAt).toISOString()}`
                };
            }
        });
        this.tools.set('set_persona', {
            name: 'set_persona',
            description: '更新智能体的 persona 信息，包括名字、描述、性格等',
            parameters: { persona_json: 'Persona JSON 对象，包含 name、description、personality、greeting 等字段' },
            execute: async (args) => {
                try {
                    const personaData = typeof args.persona_json === 'string' ? JSON.parse(args.persona_json) : args.persona_json;
                    const now = new Date().toISOString();
                    const newPersona = {
                        name: personaData.name || this.identity.name,
                        description: personaData.description || '',
                        capabilities: personaData.capabilities || [],
                        personality: personaData.personality || '',
                        greeting: personaData.greeting || '',
                        interests: personaData.interests || [],
                        createdAt: this.persona?.createdAt || now,
                        updatedAt: now
                    };
                    await this.setPersona(newPersona);
                    this.persona = newPersona;
                    if (newPersona.name) {
                        this.identity.name = newPersona.name;
                    }
                    return { success: true, output: `Persona 已更新:\n名称: ${newPersona.name}\n描述: ${newPersona.description}\n性格: ${newPersona.personality}` };
                }
                catch (e) {
                    return { success: false, error: `更新 persona 失败: ${String(e)}` };
                }
            }
        });
        this.tools.set('get_operation_logs', {
            name: 'get_operation_logs',
            description: '获取约束层的操作日志',
            parameters: {},
            execute: async () => {
                const logs = this.constraintLayer.getLogs();
                if (logs.length === 0) {
                    return { success: true, output: '暂无操作日志' };
                }
                return {
                    success: true,
                    output: `操作日志 (${logs.length} 条):\n${logs.slice(-10).map(l => `[${new Date(l.timestamp).toISOString()}] ${l.action} - ${l.status}`).join('\n')}`
                };
            }
        });
        // 添加文件列表工具
        this.tools.set('list_files', {
            name: 'list_files',
            description: '列出目录中的文件',
            parameters: { path: '目录路径（可选，默认为当前目录）' },
            execute: async (args) => {
                try {
                    const fs = await import('fs');
                    const path = args.path || this.cwd;
                    const files = fs.readdirSync(path);
                    return {
                        success: true,
                        output: `📁 目录 ${path} 中的文件 (${files.length} 个):\n${files.slice(0, 20).map(f => `  - ${f}`).join('\n')}${files.length > 20 ? '\n  ...' : ''}`
                    };
                }
                catch (e) {
                    return { success: false, error: String(e) };
                }
            }
        });
        // 添加目录读取工具（更完整的实现）
        this.tools.set('read_directory', {
            name: 'read_directory',
            description: '读取目录内容，返回文件列表和目录结构',
            parameters: { path: '目录路径（可选，默认为当前目录）' },
            execute: async (args) => {
                try {
                    const fs = await import('fs');
                    const pathModule = await import('path');
                    const targetPath = args.path || this.cwd;
                    const items = fs.readdirSync(targetPath);
                    const result = [];
                    for (const item of items.slice(0, 30)) {
                        const fullPath = pathModule.join(targetPath, item);
                        try {
                            const stat = fs.statSync(fullPath);
                            const type = stat.isDirectory() ? '📁' : '📄';
                            result.push(`${type} ${item}${stat.isDirectory() ? '/' : ''}`);
                        }
                        catch {
                            result.push(`📄 ${item}`);
                        }
                    }
                    return {
                        success: true,
                        output: `📂 ${targetPath} (${items.length} 项):\n${result.join('\n')}${items.length > 30 ? '\n... 还有更多文件' : ''}`
                    };
                }
                catch (e) {
                    return { success: false, error: `无法读取目录: ${String(e)}` };
                }
            }
        });
        // P2P Document Tools
        for (const tool of p2pDocumentTools) {
            this.tools.set(tool.name, tool);
        }
        // Shell Exec 工具: 给 AI 跑受限的 shell 命令
        // **只能** 跑白名单内的命令 (git/npm/tsc/vitest/cat/...)
        // **不能** 改禁区路径 (见 shell-guard.ts 的 FORBIDDEN_PATH_PATTERNS)
        // 沙箱 cwd: .bolloon-shell-sandbox/
        this.tools.set('shell_exec', {
            name: 'shell_exec',
            description: '在沙箱里跑 shell 命令. 仅支持白名单内命令: git, npm, npx, tsx, tsc, vitest, cat, head, tail, ls, wc, echo, pwd, date, mkdir, touch. 禁止管道/重定向/rm -rf/sudo. 命中护栏黑名单会被拒.',
            parameters: { command: '可执行文件 (必填, 必须在白名单)', args: '参数数组, 逗号分隔', timeoutMs: '超时毫秒, 默认 30000' },
            execute: async (args) => {
                const cmd = String(args.command || '').trim();
                if (!cmd)
                    return { success: false, error: 'command 必填' };
                const argList = String(args.args || '').split(',').map(s => s.trim()).filter(Boolean);
                const timeoutMs = Number(args.timeoutMs) || 30000;
                const result = await shellExec(cmd, argList, { timeoutMs });
                if (result.deniedByGuard) {
                    return { success: false, error: result.error };
                }
                if (!result.success) {
                    return { success: false, error: result.error, output: result.output };
                }
                return { success: true, output: result.output };
            }
        });
        // self_improve 工具: AI 触发自我改进循环
        // **必须** 在 branchPrefix 命名的分支上工作
        // 心跳事件会自动调用; 用户对话里也能手动调
        this.tools.set('self_improve', {
            name: 'self_improve',
            description: `触发自我改进循环. AI 会在分支 ${getBranchPrefix()}<timestamp> 上工作, 跑 tsc + vitest 验证, 通过后输出分支名给用户审. 冷却期由策略文件决定. 命中护栏禁区的改动会被拒.`,
            parameters: { goal: '本轮改进目标 (1 句话)' },
            execute: async (args) => {
                const goal = String(args.goal || '').trim();
                if (!goal)
                    return { success: false, error: 'goal 必填' };
                return await runSelfImproveLoop(goal);
            }
        });
        // list_skills 工具: 列出当前 session 已加载的 skills
        // 加载源: ~/.bolloon/skills/ → <cwd>/.bolloon/skills/ → ~/.boll/skills/
        this.tools.set('list_skills', {
            name: 'list_skills',
            description: '列出当前 session 已加载的 skills 及其描述. Skills 是从 SKILL.md 文件加载的, 兼容 Anthropic Agent Skills 标准 frontmatter 和 bollharness 现有 frontmatter.',
            parameters: {},
            execute: async () => {
                const skills = this.skillRegistry.list();
                if (skills.length === 0) {
                    return {
                        success: true,
                        output: '当前 session 没有加载任何 skill. 检查 ~/.bolloon/skills/ 或项目 .bolloon/skills/ 目录.',
                    };
                }
                const lines = skills.map((s, i) => `${i + 1}. ${s.name} — ${s.description}`);
                return { success: true, output: `已加载 ${skills.length} 个 skill:\n${lines.join('\n')}` };
            }
        });
        // use_skill 工具: 加载指定 skill 的 body 进 LLM context
        // Skills 协议核心: 把 SKILL.md body 作为 Markdown 指南返回, LLM 下一轮按它执行
        this.tools.set('use_skill', {
            name: 'use_skill',
            description: '按名称加载一个 skill, 把它的 SKILL.md body 作为 Markdown 文档返回. 调用后 LLM 会在下一轮按 skill 指南执行. 与 shell_exec / read_document 这些 "能力工具" 不同, use_skill 是 "知识注入".',
            parameters: { name: 'skill 名称 (用 list_skills 查可用的)' },
            execute: async (args) => {
                const name = String(args.name || '').trim();
                if (!name)
                    return { success: false, error: 'name 必填' };
                if (!this.skillRegistry.has(name)) {
                    const available = this.skillRegistry.list().map((s) => s.name).join(', ');
                    return { success: false, error: `skill "${name}" 未找到. 已加载: ${available || '(无)'}` };
                }
                try {
                    const body = await this.skillRegistry.execute(name, {});
                    return { success: true, output: body };
                }
                catch (e) {
                    return { success: false, error: `执行 skill 失败: ${String(e)}` };
                }
            }
        });
    }
    async registerP2PDocumentReceiver() {
        await initDocumentReceiver();
    }
    getToolDefinitions() {
        const defs = ['可用工具:'];
        for (const tool of this.tools.values()) {
            const params = Object.entries(tool.parameters).map(([k, v]) => `${k}: ${v}`).join(', ');
            defs.push(`- ${tool.name}(${params}) - ${tool.description}`);
        }
        return defs.join('\n');
    }
    async initSession() {
        await this.sessionManager.initialize();
        await this.agentsManager.initialize();
        this.persona = this.sessionManager.getPersona();
        if (this.persona?.name) {
            this.identity.name = this.persona.name;
        }
    }
    createDefaultIdentity() {
        return {
            did: `did:pi:${this.peerId.substring(0, 16)}`,
            name: `Agent-${this.peerId.substring(0, 8)}`,
            publicKey: this.peerId,
            createdAt: Date.now()
        };
    }
    checkMinimax() {
        try {
            getMinimax();
            return true;
        }
        catch {
            return false;
        }
    }
    async prompt(input) {
        this.minimaxAvailable = this.checkMinimax();
        this.messageHistory.push({
            role: 'user',
            content: input
        });
        if (!this.minimaxAvailable) {
            const response = await this.handleFallback(input);
            this.messageHistory.push({ role: 'assistant', content: response });
            return response;
        }
        return this.runReActLoop();
    }
    async promptStream(input, onStream) {
        this.minimaxAvailable = this.checkMinimax();
        this.messageHistory.push({
            role: 'user',
            content: input
        });
        onStream({ type: 'thinking', content: '🤔 开始思考...' });
        if (!this.minimaxAvailable) {
            const response = await this.handleFallback(input);
            this.messageHistory.push({ role: 'assistant', content: response });
            onStream({ type: 'done', content: '' });
            return response;
        }
        const result = await this.runReActLoop(onStream);
        onStream({ type: 'done', content: '' });
        return result;
    }
    async promptWithPivotLoop(input, config) {
        if (!this.minimaxAvailable) {
            const response = await this.handleFallback(input);
            return {
                success: false,
                response,
                iterations: 0,
                toolCalls: 0,
                qualityScore: 0,
                exitReason: 'error',
                state: {
                    iteration: 0,
                    totalTokens: 0,
                    toolCallsCount: 0,
                    consecutiveNoProgress: 0,
                    qualityScores: [],
                    pendingToolUses: [],
                    lastMeaningfulWork: 0
                }
            };
        }
        const llm = getMinimax();
        const loopConfig = config || this.pivotLoopConfig || createDefaultPivotConfig();
        const loop = new WorkflowPivotLoop(loopConfig);
        for (const tool of this.tools.values()) {
            loop.registerTool(tool);
        }
        const personaSection = this.persona ? `
角色描述: ${this.persona.description || '无'}
性格特点: ${this.persona.personality || '无'}
问候语: ${this.persona.greeting || '无'}
` : '';
        const systemPrompt = `你是 ${this.identity.name}，基于ReAct (Reasoning + Acting)模式工作。${personaSection}
当前工作目录: ${this.cwd}
当前身份: ${this.identity.name} (${this.identity.did})

${this.getToolDefinitions()}

工作模式:
1. 理解用户自然语言请求
2. 分析需要哪些工具来完成
3. 按顺序调用工具并观察结果
4. 根据观察结果决定下一步
5. 最终给出完整回答

重要:
- 每次只调用一个工具
- 仔细分析工具返回结果
- 当任务完成时，必须在回答末尾添加 <final gen> 标记表示结束
- 如果需要更多信息，继续调用工具`;
        const result = await loop.execute(input, llm, systemPrompt);
        this.messageHistory.push({ role: 'user', content: input });
        if (result.response) {
            this.messageHistory.push({ role: 'assistant', content: result.response });
        }
        return result;
    }
    async runReActLoop(onStream) {
        const llm = getMinimax();
        let iteration = 0;
        let finalResponse = '';
        let lastQualityScore = 0;
        let refineAttempts = 0;
        let consecutiveErrors = 0;
        const MAX_CONSECUTIVE_ERRORS = 3;
        // 发送循环开始的事件
        if (onStream) {
            onStream({ type: 'status', content: '🔄 开始 ReAct 循环...', tool: 'system' });
        }
        while (iteration < this.MAX_REACT_ITERATIONS) {
            iteration++;
            // 调试日志：显示每次循环开始
            console.log(`[PiAgent] 循环 ${iteration}/${this.MAX_REACT_ITERATIONS} 开始`);
            if (onStream) {
                onStream({ type: 'status', content: `🔄 循环 ${iteration}/${this.MAX_REACT_ITERATIONS}`, tool: 'loop' });
            }
            const context = this.buildContext();
            const toolDefs = this.getToolDefinitions();
            // 动态构建 refine 上下文
            let refineContext = '';
            if (refineAttempts > 0 && lastQualityScore < this.QUALITY_THRESHOLD) {
                refineContext = `\n【改进提示】上轮结果质量分 ${(lastQualityScore * 10).toFixed(1)}/10，请改进回答。`;
            }
            // 连续错误时的额外提示
            if (consecutiveErrors > 0) {
                refineContext += `\n【错误提示】上轮发生 ${consecutiveErrors} 次错误，请重新分析问题或换一种方式处理。`;
            }
            const personaSection = this.persona ? `
角色描述: ${this.persona.description || '无'}
性格特点: ${this.persona.personality || '无'}
问候语: ${this.persona.greeting || '无'}
` : '';
            const systemPrompt = `你是 ${this.identity.name}，基于ReAct (Reasoning + Acting)模式工作。${personaSection}
当前工作目录: ${this.cwd}
当前身份: ${this.identity.name} (${this.identity.did})
${refineContext}

${toolDefs}

工作模式:
1. 理解用户自然语言请求
2. 分析需要哪些工具来完成
3. 按顺序调用工具并观察结果
4. 根据观察结果决定下一步
5. 最终给出完整回答

重要:
- 每次只调用一个工具
- 仔细分析工具返回结果
- 当任务完成时，必须在回答末尾添加 <final gen> 标记表示结束
- 如果需要更多信息，继续调用工具`;
            const response = await llm.chat(context, systemPrompt);
            const reply = response.reply.trim();
            console.log(`[PiAgent] LLM 回复长度: ${reply.length}, 内容预览: "${reply.substring(0, 80)}..."`);
            // 通知前端：收到 LLM 回复
            if (onStream) {
                onStream({ type: 'token', content: reply.substring(0, 100) });
            }
            if (this.isFinalResponse(reply)) {
                // 检查质量分数
                lastQualityScore = this.estimateResponseQuality(reply);
                // 如果质量太低且还有改进机会，进入改进循环
                if (lastQualityScore < this.QUALITY_THRESHOLD && refineAttempts < this.MAX_REFINE_ATTEMPTS) {
                    refineAttempts++;
                    console.log(`[PiAgent] 质量评分 ${(lastQualityScore * 10).toFixed(1)}/10 < ${(this.QUALITY_THRESHOLD * 10).toFixed(1)}/10，自动改进中 (${refineAttempts}/${this.MAX_REFINE_ATTEMPTS})`);
                    continue;
                }
                finalResponse = this.extractFinalAnswer(reply);
                break;
            }
            const toolCall = this.parseToolCall(reply);
            if (toolCall) {
                this.messageHistory.push({
                    role: 'assistant',
                    content: reply,
                    toolCall
                });
                // 通知前端：检测到工具调用
                if (onStream) {
                    onStream({ type: 'tool', content: `🔧 调用工具: ${toolCall.name}`, tool: toolCall.name });
                    if (toolCall.args && Object.keys(toolCall.args).length > 0) {
                        onStream({ type: 'status', content: `📋 参数: ${JSON.stringify(toolCall.args)}`, tool: toolCall.name });
                    }
                }
                const tool = this.tools.get(toolCall.name);
                if (!tool) {
                    consecutiveErrors++;
                    const errorResult = { success: false, error: `未知工具: ${toolCall.name}` };
                    this.messageHistory.push({ role: 'tool', content: JSON.stringify(errorResult), toolResult: errorResult });
                    this.logToHarness(toolCall.name, toolCall.args, errorResult);
                    console.warn(`[PiAgent] 未知工具: ${toolCall.name}，跳过并继续`);
                    continue;
                }
                try {
                    const result = await tool.execute(toolCall.args);
                    console.log(`[PiAgent] 工具 ${toolCall.name} 执行完成: success=${result.success}`);
                    this.messageHistory.push({ role: 'tool', content: JSON.stringify(result), toolResult: result });
                    this.logToHarness(toolCall.name, toolCall.args, result);
                    // 通知前端工具执行结果
                    if (onStream) {
                        if (result.success) {
                            onStream({ type: 'status', content: `✅ ${toolCall.name} 执行成功`, tool: toolCall.name });
                            if (result.output) {
                                const outputPreview = result.output.substring(0, 200);
                                onStream({ type: 'tool', content: `📤 结果: ${outputPreview}${result.output.length > 200 ? '...' : ''}`, tool: toolCall.name });
                            }
                        }
                        else {
                            onStream({ type: 'error', content: `❌ ${toolCall.name} 执行失败: ${result.error}`, tool: toolCall.name });
                        }
                    }
                    if (result.success) {
                        consecutiveErrors = 0; // 重置连续错误计数
                        // 检查工具执行质量
                        lastQualityScore = this.estimateToolResultQuality(result);
                        if (lastQualityScore < this.QUALITY_THRESHOLD && refineAttempts < this.MAX_REFINE_ATTEMPTS) {
                            refineAttempts++;
                            console.log(`[PiAgent] 工具结果质量低，自动重试 (${refineAttempts}/${this.MAX_REFINE_ATTEMPTS})`);
                        }
                        else {
                            console.log(`[PiAgent] 工具执行成功，质量评分: ${(lastQualityScore * 10).toFixed(1)}/10`);
                        }
                        // 工具执行成功后，继续循环获取下一个 LLM 响应
                        if (onStream) {
                            onStream({ type: 'status', content: `🔄 工具执行完成，继续循环...`, tool: 'loop' });
                        }
                        // 不 break，继续下一次循环
                    }
                    else {
                        consecutiveErrors++;
                        console.warn(`[PiAgent] 工具执行失败 (${consecutiveErrors}/${MAX_CONSECUTIVE_ERRORS}): ${result.error}`);
                        // 连续错误达到上限，尝试换一种方式
                        if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
                            console.log(`[PiAgent] 连续 ${MAX_CONSECUTIVE_ERRORS} 次错误，尝试换一种方式处理`);
                            // 添加错误上下文，让 LLM 换一种方式
                            this.messageHistory.push({
                                role: 'system',
                                content: `[注意] 前面的工具调用连续失败。请尝试其他工具或换一种方式完成用户请求。`
                            });
                            consecutiveErrors = 0; // 重置以继续尝试
                        }
                    }
                }
                catch (execError) {
                    consecutiveErrors++;
                    const errorResult = { success: false, error: String(execError) };
                    this.messageHistory.push({ role: 'tool', content: JSON.stringify(errorResult), toolResult: errorResult });
                    this.logToHarness(toolCall.name, toolCall.args, errorResult);
                    console.error(`[PiAgent] 工具执行异常: ${execError}`);
                }
            }
            else {
                // LLM 返回的不是 tool call 格式
                this.messageHistory.push({
                    role: 'assistant',
                    content: reply
                });
                // 通知前端收到非工具调用回复
                if (onStream) {
                    onStream({ type: 'token', content: reply.substring(0, 150) });
                }
                // 检查是否需要继续循环处理
                // 更严格的判断：只有当回复明确表示需要更多信息时才继续
                const containsToolCallIntent = reply.includes('调用工具') || reply.includes('tool(') ||
                    reply.includes('使用工具') || reply.includes('需要获取') || reply.includes('需要查看') ||
                    // 兼容 LLM 用对象字面量输出 tool call (上轮没解析成功时, 至少要继续)
                    reply.includes('tool =>') || reply.includes('[TOOL_CALL]');
                const hasError = ['不存在', '找不到', '无法找到', 'not found', 'does not exist',
                    '错误', 'error', '失败', 'failed'].some(k => reply.includes(k));
                const isTooShort = reply.length < 50 && reply.length > 0;
                const hasQuestion = reply.includes('?') && (reply.includes('怎么') || reply.includes('如何') || reply.includes('什么'));
                const needsMoreWork = hasError || containsToolCallIntent || isTooShort || hasQuestion;
                if (needsMoreWork && iteration < this.MAX_REACT_ITERATIONS) {
                    console.log(`[PiAgent] 继续循环处理 (${iteration}/${this.MAX_REACT_ITERATIONS}): needsMoreWork=${needsMoreWork}, hasError=${hasError}, containsToolCallIntent=${containsToolCallIntent}`);
                    if (onStream) {
                        onStream({ type: 'status', content: `🔄 继续处理，循环 ${iteration}...`, tool: 'loop' });
                    }
                    continue;
                }
                // 否则把这个当作可能的最终回答
                finalResponse = reply;
                if (onStream) {
                    onStream({ type: 'status', content: `📝 提取最终回答，长度 ${reply.length}`, tool: 'system' });
                }
                break;
            }
        }
        if (!finalResponse) {
            finalResponse = '任务处理超时，请尝试更具体的请求。';
            if (onStream) {
                onStream({ type: 'error', content: '⚠️ 任务处理超时', tool: 'system' });
            }
        }
        // 通知前端循环完成
        if (onStream) {
            onStream({ type: 'status', content: `✅ 处理完成，共 ${iteration - 1} 次循环`, tool: 'system' });
        }
        const now = new Date().toISOString();
        const identityPrefix = `${this.identity.name} ｜ bolloon 智能体
<environment_details>
Current time: ${now}
Working directory: ${this.cwd}
Workspace root folder: ${this.cwd}
</environment_details>
`;
        finalResponse = identityPrefix + finalResponse;
        this.messageHistory.push({ role: 'assistant', content: finalResponse });
        return finalResponse;
    }
    async deepThink(prompt) {
        const result = await this.thinkingEngine.think(prompt);
        let response = `深度思考完成（${result.depth}层）:\n\n`;
        for (const step of result.steps) {
            response += `第${step.step}步: ${step.thought}\n`;
            if (step.reflection) {
                response += `  反思: ${step.reflection}\n`;
            }
            if (step.improvement) {
                response += `  改进: ${step.improvement}\n`;
            }
            response += '\n';
        }
        response += `最终输出: ${result.finalOutput}`;
        return { result, response };
    }
    async processDocumentsInParallel(paths, operation, requirements) {
        if (paths.length === 0) {
            return { outputs: [], success: true };
        }
        const subtasks = paths.map((filePath, index) => ({
            id: `doc-${index}`,
            description: `${operation}:${filePath}${requirements ? `:${requirements}` : ''}`,
            priority: index
        }));
        const dispatchPrompts = subtasks.map(t => t.description);
        const results = await this.coordinator.dispatch(dispatchPrompts.join(' ||| '), paths.length);
        const outputs = [];
        let allSuccess = true;
        for (let i = 0; i < paths.length; i++) {
            const result = results.find((r) => r.taskId === `task-${i}`);
            if (result) {
                outputs.push(result.output);
                if (!result.success)
                    allSuccess = false;
            }
            else {
                outputs.push(`No result for ${paths[i]}`);
                allSuccess = false;
            }
        }
        return { outputs, success: allSuccess };
    }
    buildContext() {
        const recentMessages = this.messageHistory.slice(-10);
        return recentMessages.map(m => {
            if (m.role === 'user')
                return `用户: ${m.content}`;
            if (m.role === 'assistant')
                return `助手: ${m.content}`;
            if (m.role === 'tool') {
                const result = m.toolResult ? JSON.stringify(m.toolResult) : m.content;
                return `工具结果: ${result}`;
            }
            return m.content;
        }).join('\n');
    }
    isFinalResponse(content) {
        // 只有明确输出 <final gen> 才认为是最终回答
        return content.includes('<final gen>');
    }
    extractFinalAnswer(content) {
        // 提取 <final gen> 后的内容作为最终回答
        const marker = '<final gen>';
        const markerIndex = content.indexOf(marker);
        if (markerIndex !== -1) {
            content = content.substring(markerIndex + marker.length).trim();
        }
        // 移除任何 tool call 标记
        let cleaned = content
            .replace(/调用工具[：:]\s*\w+\s*\([^)]*\)/g, '')
            .replace(/使用工具[：:]\s*\w+\s*\([^)]*\)/g, '')
            .replace(/tool[_\w]*[：:]\s*\w+\s*\([^)]*\)/gi, '')
            .trim();
        return cleaned;
    }
    parseToolCall(content) {
        const patterns = [
            /调用工具[：:]\s*(\w+)\s*\(([^)]*)\)/,
            /使用工具[：:]\s*(\w+)\s*\(([^)]*)\)/,
            /tool[_\w]*[：:]\s*(\w+)\s*\(([^)]*)\)/i,
            /(\w+)\s*\(\s*([^)]*)\s*\)/,
            // 兼容 LLM 输出的对象字面量格式: {tool => "get_identity", args => {...}}
            /\{\s*tool\s*=>\s*["'](\w+)["']\s*(?:,\s*args\s*=>\s*(\{[\s\S]*?\}))?\s*\}/,
            // 兼容: tool => "get_identity"  (无 args 包裹)
            /\btool\s*=>\s*["'](\w+)["']/,
            // 兼容: [TOOL_CALL] 块内 JSON 形式 {"name": "x", "args": {...}}
            /\[TOOL_CALL\][\s\S]*?\{\s*"name"\s*:\s*"(\w+)"\s*,\s*"args"\s*:\s*(\{[\s\S]*?\})/i,
        ];
        for (const pattern of patterns) {
            const match = content.match(pattern);
            if (match) {
                const name = match[1];
                let args = {};
                const rawArgs = match[2] || '';
                if (rawArgs && rawArgs.trim().startsWith('{')) {
                    // JSON 形式, 尝试解析
                    try {
                        const parsed = JSON.parse(rawArgs);
                        if (parsed && typeof parsed === 'object') {
                            args = Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, String(v)]));
                        }
                    }
                    catch {
                        // 解析失败就当字符串处理
                        const argPairs = rawArgs.split(',').map(s => s.trim()).filter(Boolean);
                        for (const pair of argPairs) {
                            const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
                            if (key)
                                args[key] = valueParts.join(':') || '';
                        }
                    }
                }
                else if (rawArgs) {
                    // 形参串, 形如 key: value, key2: value2
                    const argPairs = rawArgs.split(',').map(s => s.trim()).filter(Boolean);
                    for (const pair of argPairs) {
                        const [key, ...valueParts] = pair.split(':').map(s => s.trim().replace(/['"]/g, ''));
                        if (key)
                            args[key] = valueParts.join(':') || '';
                    }
                }
                if (this.tools.has(name) || this.tools.has(name.replace(/_/g, '_'))) {
                    return { name, args };
                }
            }
        }
        return null;
    }
    estimateResponseQuality(response) {
        let score = 0.5;
        if (response.length > 50)
            score += 0.1;
        if (response.length > 200)
            score += 0.1;
        if (response.length < 20)
            score -= 0.3;
        if (response.includes('\n'))
            score += 0.1;
        if (response.includes('-') || response.includes('•'))
            score += 0.05;
        if (response.includes('```'))
            score += 0.1;
        const conclusionWords = ['完成', '结果', '总结', '所以', '因此', '答案', '推荐'];
        if (conclusionWords.some(w => response.includes(w)))
            score += 0.1;
        if (response.includes('调用工具') || response.includes('tool('))
            score -= 0.2;
        return Math.max(0, Math.min(1, score));
    }
    estimateToolResultQuality(result) {
        let score = 0.5;
        if (!result.success)
            return 0.2;
        if (result.output) {
            score += 0.2;
            if (result.output.length > 50)
                score += 0.1;
            if (result.output.length < 10)
                score -= 0.1;
            if (result.output.includes('❌') || result.output.includes('error'))
                score -= 0.2;
            if (result.output.includes('✅') || result.output.includes('success'))
                score += 0.1;
        }
        if (result.error)
            score -= 0.3;
        return Math.max(0, Math.min(1, score));
    }
    async handleFallback(input) {
        const lowerInput = input.toLowerCase();
        const parts = input.trim().split(/\s+/);
        const cmd = parts[0].toLowerCase();
        const args = parts.slice(1).join(' ');
        if (cmd.includes('读取') || cmd === 'read' || cmd === 'read_document') {
            if (args)
                return await this.readDocument(args);
        }
        if (cmd.includes('总结') || cmd === 'summary' || cmd === 'summarize') {
            if (args)
                return await this.summarizeText(args);
        }
        if (cmd.includes('改进') || cmd === 'improve' || cmd === 'improve_document') {
            const match = input.match(/改进[^\w]+(.+)/i) || input.match(/improve\s+(.+)/i);
            if (match) {
                return `改进需要LLM支持，请设置 MINIMAX_API_KEY 环境变量。\n文件: ${match[1]}`;
            }
        }
        if (cmd.includes('节点') || cmd === 'peers' || cmd === 'list_peers') {
            return this.listPeers();
        }
        if (cmd.includes('身份') || cmd === 'identity' || cmd === 'get_identity') {
            return JSON.stringify(this.getIdentity(), null, 2);
        }
        if (cmd.includes('日志') || cmd === 'logs') {
            const logs = this.constraintLayer.getLogs();
            if (logs.length === 0)
                return '暂无操作日志';
            return logs.slice(-5).map(l => `[${new Date(l.timestamp).toISOString()}] ${l.action}`).join('\n');
        }
        return this.getDefaultResponse(input);
    }
    static OPERATIONS_REFERENCE = null;
    static getOperationsReference() {
        if (this.OPERATIONS_REFERENCE === null) {
            try {
                const refPath = path.join(process.cwd(), 'src', 'bollharness', 'scripts', 'context-fragments', 'pi-agent-operations.md');
                this.OPERATIONS_REFERENCE = fsSync.readFileSync(refPath, 'utf-8');
            }
            catch {
                this.OPERATIONS_REFERENCE = '';
            }
        }
        return this.OPERATIONS_REFERENCE;
    }
    getDefaultResponse(input) {
        const operationsRef = PiAgentSession.getOperationsReference();
        if (operationsRef) {
            return `收到了: "${input}"

我是一个判断力处理智能体，支持自然语言交互。

可用操作（直接说出即可）:
${this.extractOperationsFromRef(operationsRef)}

示例请求:
  - "读取 src/index.ts 文件"
  - "总结一下 README.md"
  - "查看当前连接了哪些节点"
  - "向 QmABC... 发送测试消息"`;
        }
        return `收到了: "${input}"

我是一个判断力处理智能体，支持自然语言交互。

可用操作（直接说出即可）:
  - "读取 README.md" - 读取并分析文档
  - "总结文档" - 总结文档内容
  - "改进文档，按照X要求" - 改进文档
  - "查看节点" - 查看已连接的对等节点
  - "向X发送消息Y" - 向对等节点发送消息
  - "广播消息X" - 广播消息到所有节点
  - "查看身份" - 查看当前智能体身份
  - "查看日志" - 查看最近操作日志

示例请求:
  - "读取 src/index.ts 文件"
  - "总结一下 README.md"
  - "查看当前连接了哪些节点"
  - "向 QmABC... 发送测试消息"`;
    }
    extractOperationsFromRef(ref) {
        const lines = ref.split('\n');
        const inOperationsSection = false;
        const operationLines = [];
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            if (line.startsWith('## 可用操作')) {
                for (let j = i + 1; j < lines.length; j++) {
                    const opLine = lines[j];
                    if (opLine.startsWith('## ') || opLine.startsWith('#'))
                        break;
                    if (opLine.includes('|') && !opLine.startsWith('|')) {
                        const parts = opLine.split('|').map(p => p.trim());
                        if (parts.length >= 3 && parts[1] && parts[2]) {
                            operationLines.push(`  - "${parts[1]}" - ${parts[2]}`);
                        }
                    }
                }
                break;
            }
        }
        return operationLines.length > 0 ? operationLines.join('\n') :
            `  - "读取 README.md" - 读取并分析文档
  - "总结文档" - 总结文档内容
  - "改进文档，按照X要求" - 改进文档
  - "查看节点" - 查看已连接的对等节点
  - "向X发送消息Y" - 向对等节点发送消息
  - "广播消息X" - 广播消息到所有节点
  - "查看身份" - 查看当前智能体身份
  - "查看日志" - 查看最近操作日志`;
    }
    async suggestRename(messages) {
        if (!this.minimaxAvailable || messages.length < 2) {
            return null;
        }
        const conversation = messages.map(m => `${m.type === 'user' ? '用户' : '助手'}: ${m.content}`).join('\n');
        const llm = getMinimax();
        try {
            const response = await llm.chat(`根据以下对话内容，为这个对话生成一个简短的名称（不超过20个字）：\n\n${conversation}\n\n直接输出名称，不要其他解释。`, '命名建议');
            const name = response.reply.trim();
            if (name && name.length <= 20 && name !== '智能体') {
                return `Agent | ${name}`;
            }
        }
        catch {
            // ignore
        }
        return null;
    }
    async summarizeText(text) {
        if (!this.minimaxAvailable) {
            return '⚠️ LLM未初始化，请设置 MINIMAX_API_KEY 环境变量';
        }
        const llm = getMinimax();
        const result = await llm.summarize(text);
        return `📝 摘要:\n${result.summary}\n\n质量评分: ${(result.qualityScore * 10).toFixed(1)}/10`;
    }
    async readDocument(filePath) {
        const content = await documentReader.read(filePath);
        this.sessionManager.addFileContext(filePath, content.text.substring(0, 1000));
        return `📄 ${content.metadata.filename}\n大小: ${content.metadata.size} 字节\n\n${content.text.substring(0, 500)}...`;
    }
    async summarizeDocument(filePath, context) {
        if (!this.minimaxAvailable) {
            return {
                summary: '⚠️ LLM未初始化，请设置 MINIMAX_API_KEY 环境变量',
                qualityScore: 0
            };
        }
        const content = await documentReader.read(filePath);
        this.sessionManager.addFileContext(filePath, content.text.substring(0, 1000));
        const llm = getMinimax();
        const chunks = documentReader.chunk(content.text);
        const summaries = [];
        let totalQuality = 0;
        for (const chunk of chunks) {
            const result = await llm.summarize(chunk, context);
            summaries.push(result.summary);
            totalQuality += result.qualityScore;
        }
        const avgQuality = totalQuality / chunks.length;
        return {
            summary: summaries.join('\n\n'),
            qualityScore: avgQuality
        };
    }
    async improveDocument(request) {
        if (!this.minimaxAvailable) {
            return {
                improved: false,
                qualityScore: 0,
                shouldAutoSend: false
            };
        }
        const content = await documentReader.read(request.originalPath);
        const llm = getMinimax();
        const improvedResult = await llm.summarize(content.text + '\n\n改进要求: ' + request.requirements, request.context);
        const shouldAutoSend = await llm.shouldAutoSend(improvedResult.qualityScore, 0.7);
        return {
            improved: true,
            newContent: improvedResult.summary,
            qualityScore: improvedResult.qualityScore,
            shouldAutoSend
        };
    }
    async runWorkflow(steps) {
        const context = {
            peers: this.getPeers(),
            logs: []
        };
        const checkResult = await this.constraintLayer.checkGuardrails(context);
        if (!checkResult.passed && checkResult.blocked) {
            console.warn(`Guardrail blocked: ${checkResult.blocked.name}`);
        }
        return this.workflowEngine.executeWorkflow(steps, context);
    }
    async summarizeDocumentWorkflow(filePath, targetPeer) {
        const steps = [
            {
                id: 'read',
                type: 'read',
                config: { path: filePath },
                retry: { max: 3, current: 0, backoffMs: 1000 },
                onFail: 'abort'
            },
            {
                id: 'summarize',
                type: 'summarize',
                config: { context: `File: ${filePath}` },
                retry: { max: 3, current: 0, backoffMs: 1000 },
                onFail: 'skip',
                guardrail: (ctx) => Promise.resolve(ctx.qualityScore !== undefined && ctx.qualityScore >= 0.5)
            }
        ];
        if (targetPeer) {
            steps.push({
                id: 'send',
                type: 'send',
                config: { peerId: targetPeer },
                retry: { max: 2, current: 0, backoffMs: 2000 },
                onFail: 'skip'
            });
        }
        return this.runWorkflow(steps);
    }
    async improveAndSendWorkflow(filePath, requirements, targetPeer) {
        const steps = [
            {
                id: 'read',
                type: 'read',
                config: { path: filePath },
                retry: { max: 3, current: 0, backoffMs: 1000 },
                onFail: 'abort'
            },
            {
                id: 'improve',
                type: 'improve',
                config: { requirements, context: `File: ${filePath}` },
                retry: { max: 2, current: 0, backoffMs: 1500 },
                onFail: 'skip'
            },
            {
                id: 'send',
                type: 'send',
                config: { peerId: targetPeer, message: '改进后的文档' },
                retry: { max: 2, current: 0, backoffMs: 2000 },
                onFail: 'skip'
            }
        ];
        return this.runWorkflow(steps);
    }
    getOperationLogs() {
        return this.constraintLayer.getLogs();
    }
    listPeers() {
        const peers = p2pNetwork.getPeers();
        if (peers.length === 0) {
            return '当前无连接的对等节点';
        }
        return `已连接节点 (${peers.length}):\n${peers.map(p => `  - ${p}`).join('\n')}`;
    }
    getPeers() {
        return p2pNetwork.getPeers();
    }
    async sendMessage(peerId, message) {
        await p2pNetwork.sendMessage(peerId, 'message', message);
    }
    async broadcast(message) {
        await p2pNetwork.broadcast('message', message);
    }
    getIdentity() {
        return { ...this.identity };
    }
    updateIdentity(updates) {
        this.identity = { ...this.identity, ...updates };
    }
    getSessionState() {
        return this.sessionManager.getState();
    }
    getMemory() {
        return this.sessionManager.getMemory();
    }
    getPersona() {
        return this.sessionManager.getPersona();
    }
    async setPersona(persona) {
        await this.sessionManager.savePersona(persona);
        this.persona = persona;
        if (persona.name) {
            this.identity.name = persona.name;
        }
    }
    getDiscoveredAgents() {
        return this.agentsManager.getAllAgents();
    }
    getSocialChannels() {
        return this.sessionManager.getAllChannels();
    }
    async sendSocialMessage(channelId, content) {
        const message = {
            id: crypto.randomUUID(),
            type: 'ai',
            content,
            sender: 'self',
            timestamp: new Date().toISOString(),
            agentId: this.identity.did
        };
        await this.sessionManager.addMessage(channelId, message);
        const channels = this.sessionManager.getAllChannels();
        const channel = channels.find(c => c.id === channelId);
        if (channel?.peerDid) {
            const agent = this.agentsManager.getAgent(channel.peerDid);
            if (agent) {
                const comm = global.hyperswarmComm;
                if (comm) {
                    const connections = comm.getConnections?.() || [];
                    for (const conn of connections) {
                        if (conn.publicKey === agent.peerId) {
                            const data = new TextEncoder().encode(`social|${JSON.stringify({ from: this.identity.did, message: content })}`);
                            comm.sendToConnection?.(conn, data);
                            break;
                        }
                    }
                }
            }
        }
    }
    async startSocialHeartbeat(config) {
        if (this.socialHeartbeat) {
            return;
        }
        this.socialHeartbeat = await createSocialHeartbeat(this.sessionManager, this.agentsManager, config);
        this.socialHeartbeat.setOnAgentDiscovered((agent) => {
            console.log(`[Agent] 发现新智能体: ${agent.name}`);
        });
        this.socialHeartbeat.setOnSocialMessage((fromDid, message, channelId) => {
            console.log(`[Agent] 收到来自 ${fromDid} 的社交消息: ${message.substring(0, 50)}...`);
        });
    }
    stopSocialHeartbeat() {
        if (this.socialHeartbeat) {
            this.socialHeartbeat.stop();
            this.socialHeartbeat = null;
        }
    }
    getSkillRegistry() {
        return this.skillRegistry;
    }
    registerSkill(skill) {
        this.skillRegistry.register(skill);
    }
    async executeSkill(name, params) {
        return this.skillRegistry.execute(name, params);
    }
    async addUserAction(content, importance) {
        await this.sessionManager.addUserActionToSharedContext(content, importance);
    }
    async addSharedKnowledge(knowledge) {
        await this.sessionManager.addSharedKnowledge(knowledge);
    }
    async getRecentActionsSummary(count) {
        return this.sessionManager.getRecentActionsSummary(count);
    }
    async getSharedKnowledge() {
        return this.sessionManager.getSharedKnowledge();
    }
    async getGlobalContextSummary() {
        return this.sessionManager.getGlobalContextSummary();
    }
    async createCooperation(type, task, toAgentId, context) {
        return this.sessionManager.createCooperation(type, task, toAgentId, context);
    }
    async getPendingCooperations() {
        return this.sessionManager.getPendingCooperations();
    }
    async updateCooperationStatus(cooperationId, status, result) {
        return this.sessionManager.updateCooperationStatus(cooperationId, status, result);
    }
    async getAllRegisteredAgents() {
        return this.sessionManager.getAllRegisteredAgents();
    }
    async findAgentByCapability(capability) {
        return this.sessionManager.findAgentByCapability(capability);
    }
    // ==================== Harness Integration ====================
    operationLog = [];
    logToHarness(action, args, result) {
        if (!this.harnessEnabled || !this.harness)
            return;
        this.operationLog.push({
            timestamp: Date.now(),
            action,
            args,
            result,
            status: result.success ? 'ok' : 'error'
        });
        if (this.operationLog.length >= 10) {
            this.archiveToHarness();
        }
    }
    archiveToHarness() {
        if (!this.harnessEnabled || !this.harness || this.operationLog.length === 0)
            return;
        this.harness.archiveSession(this.operationLog);
        this.operationLog = [];
    }
    getHarnessContext() {
        if (!this.harnessEnabled || !this.harness) {
            return 'Harness not available';
        }
        return this.harness.getSessionContext();
    }
    isHarnessEnabled() {
        return this.harnessEnabled;
    }
    getHarness() {
        return this.harness;
    }
    getOperationLog() {
        return [...this.operationLog];
    }
}
let sessionInstance = null;
let lastIdentityDid = null;
// 独立的 session 实例缓存（用于多 session 支持）
const independentSessions = new Map();
export async function createAgentSession(config, forceNew) {
    const incomingDid = config.identityDoc?.did;
    // 如果有独立的 peerId (包含 :)，使用它作为 key
    if (config.peerId && config.peerId.includes(':')) {
        const key = config.peerId;
        if (!forceNew && independentSessions.has(key)) {
            console.log(`[createAgentSession] 找到现有独立 session, key=${key}`);
            return independentSessions.get(key);
        }
        const session = new PiAgentSession(config);
        independentSessions.set(key, session);
        console.log(`[createAgentSession] 创建独立 session, key=${key}, DID=${incomingDid}`);
        return session;
    }
    // 如果指定了 forceNew 但没有 peerId，生成带时间戳的 key
    if (forceNew) {
        const key = `force:${Date.now()}`;
        const session = new PiAgentSession(config);
        independentSessions.set(key, session);
        console.log(`[createAgentSession] 创建强制新 session, key=${key}`);
        return session;
    }
    // 如果有新的 DID，强制重建 session
    if (sessionInstance && lastIdentityDid && incomingDid && lastIdentityDid !== incomingDid) {
        console.log(`[createAgentSession] DID 变化 ${lastIdentityDid} -> ${incomingDid}，重建 session`);
        sessionInstance = null;
    }
    if (sessionInstance) {
        // 检查是否需要更新 identity
        const currentDid = sessionInstance.getIdentity().did;
        if (incomingDid && currentDid !== incomingDid) {
            console.log(`[createAgentSession] 更新 identity: ${currentDid} -> ${incomingDid}`);
            sessionInstance.updateIdentity({
                did: incomingDid,
                name: config.identityDoc?.name || sessionInstance.getIdentity().name,
                publicKey: config.identityDoc?.publicKey || '',
                createdAt: Date.now()
            });
        }
        return sessionInstance;
    }
    sessionInstance = new PiAgentSession(config);
    lastIdentityDid = config.identityDoc?.did || null;
    console.log(`[createAgentSession] 新建 session, DID=${lastIdentityDid}`);
    return sessionInstance;
}
export function getAgentSession() {
    return sessionInstance;
}
export function resetAgentSession() {
    sessionInstance = null;
    lastIdentityDid = null;
}
/**
 * 自我改进循环: 在沙箱分支上工作, 输出结果给用户审.
 *
 * 不在 PiAgent 实例上的原因: 心跳回调可能没有 agent 实例, 单独函数更易复用.
 *
 * **关键不变量**:
 *   1. AI 不能 push 到 master (shell-guard 黑名单 + git 受保护分支)
 *   2. 改动必须走沙箱分支 (SELF_IMPROVE_BRANCH_PREFIX)
 *   3. 6 小时冷却期 (SELF_IMPROVE_COOLDOWN_MS)
 *   4. 写文件必须经过 shell_exec + 护栏检查
 */
let lastSelfImproveAt = null;
export async function runSelfImproveLoop(goal) {
    const cooldownMs = getCooldownMs();
    // 1. 冷却期检查
    if (lastSelfImproveAt && Date.now() - lastSelfImproveAt < cooldownMs) {
        const waitHrs = Math.ceil((cooldownMs - (Date.now() - lastSelfImproveAt)) / 3600000);
        return { success: false, error: `自改冷却中, 还需要约 ${waitHrs} 小时` };
    }
    // 2. 选源分支 + 新分支名
    const sourceBranch = 'master';
    const newBranch = `${getBranchPrefix()}${Date.now()}`;
    console.log(`[self-improve] 启动自改循环, 目标: ${goal}, 新分支: ${newBranch}`);
    // 3. 创建分支
    const r1 = await shellExec('git', ['checkout', sourceBranch]);
    if (!r1.success)
        return { success: false, error: `切换到 ${sourceBranch} 失败: ${r1.error}` };
    const r2 = await shellExec('git', ['checkout', '-b', newBranch]);
    if (!r2.success)
        return { success: false, error: `创建分支失败: ${r2.error}` };
    // 4. 走 task queue: 把"自改"作为一个 task 抛回去, AI 拿到后会用 shell_exec 改
    //    护栏已经阻止所有禁区改动, 这里只负责登记
    lastSelfImproveAt = Date.now();
    return {
        success: true,
        output: `✅ 自改分支已创建: ${newBranch}\n目标: ${goal}\n\n**护栏已激活**:\n  - 仅允许白名单命令 (git/npm/tsc/vitest/cat/ls/...)\n  - 禁止改 src/agents/pi-sdk.ts, shell-guard.ts, src/heartbeat/, src/network/, src/pi-ecosystem-judgment/, package.json, .env 等\n  - 6 小时冷却期\n\nAI 接下来会用 shell_exec 工具改源码. 完成后你会在对话里看到 diff 摘要, 手动 git diff master..${newBranch} 审, 满意再 merge.`
    };
}
