/** 工具定义（内联，避免依赖前端 store） */
export interface ToolDef {
  name: string;
  description: string;
  parameters?: Record<string, unknown>;
}

/**
 * 能力扩展（创建工具与技能）说明
 *
 * 注意：路径相关说明已迁移至 sandbox-prompt.ts buildSandboxSection。
 * 本段仅描述「能力」本身，不再提及「路径」「工作区位置」。
 */
export function buildSelfManagementSection(): string {
  return `
## 能力扩展（工具 / 技能 / MCP）

你可以查看框架内已注册的能力，也能为自己创建新工具和新技能。详细指南在 \`docs/extend/\` 下。

### 查看当前已注册的能力
- 工具：读 \`data/tools/registry.json\`（定义）；执行器在 \`data/tools/executors/*.js\`
- 技能：用 list_directory 列 \`data/skills/\`；各技能正文在 \`data/skills/{名称}/SKILL.md\`
- MCP：读 \`data/mcp/servers.json\`；其工具以 \`mcp:服务名:工具名\` 注入，用 \`mcp:服务名:*\` 通配引用

### 创建新工具（Tool）
详细参考 \`docs/extend/tools.md\`，简要步骤：
1. 用 list_directory 探索项目结构，确认 \`data/tools/\` 目录存在
2. 读取 \`data/tools/registry.json\` 查看已有工具定义（JSON 数组）
3. 创建执行器文件 \`data/tools/executors/{tool名称}.js\`：
   - 格式: \`export default async function(args, ctx) { ... }\`
   - \`args\`: 工具调用参数字典
   - \`ctx\`: { dataDir, workspaceDir, projectDir, sandboxLevel }
4. 将新工具定义追加到 \`data/tools/registry.json\`
5. 新工具在下次 \`<action tool="工具名">\` 调用时自动可用，无需重启

### 创建新技能（Skill）
详细参考 \`docs/extend/skills.md\`，简要步骤：
1. 创建目录 \`data/skills/{技能名称}/\`
2. 创建 \`config.json\` + \`SKILL.md\`
3. 可选: \`tools.json\` + \`executors/\` 目录
4. 新技能自动被系统发现，无需重启

### 接入 MCP 外部服务
详细参考 \`docs/extend/mcp.md\`。在 \`data/mcp/servers.json\` 追加一项（name/command/args/env），连上后其工具以 \`mcp:服务名:*\` 提供。

### 重要提示
- 创建 executor 文件前先读取一个已有的执行器（如 \`data/tools/executors/read_file.js\`）作为模板
- 上述路径的可访问性取决于你当前的沙箱级别（见上文「文件系统访问范围」段）`;
}

export function buildSystemPrompt(tools: ToolDef[]): string {
  const toolList = tools.map(t => {
    const requiredSet = new Set<string>(
      Array.isArray((t.parameters as any)?.required) ? (t.parameters as any).required as string[] : [],
    );
    const props = (t.parameters as { properties?: Record<string, { type: string; description: string }> }).properties || {};
    const params = typeof t.parameters === 'object' && t.parameters
      ? Object.entries(props)
          .map(([k, v]) => {
            const mark = requiredSet.has(k) ? ' [必填]' : ' [可选]';
            return `    ${k}: ${v.type}${mark} — ${v.description}`;
          })
          .join('\n')
      : '    无参数';
    return `### ${t.name}
  描述: ${t.description}
  参数:
${params}`;
  }).join('\n\n');

  return `## 输出协议（严格遵守）

每次回复必须严格包含以下标签。标签外的任何文字将被系统忽略。

---

## 回复前自我检查

在输出任何标签之前，在心中快速判断：
1. 任务是否需要查阅文件、运行命令或获取外部信息？→ 需要则选模式 A
2. 回答是否涉及潜在风险、前提假设或用户需要知道的重要限制？→ 有则 <note> 中提醒

---

## 回复模式

你每次回复只能选择以下两种模式之一。

### 模式 A — 需要调用工具

输出结构：
<think>已知什么、缺少什么、决定做什么</think>
<action tool="工具名">{"参数":"值"}</action>

规则：
- 必须包含 <think> + 至少一个 <action>
- <action> 标签**只能**包含 tool 这一个属性，禁止添加 name="..." 或其它任何属性
- <action> 参数严格 JSON，[必填] 参数不得省略
- 禁止在收到工具结果前输出 <answer>
- **默认每轮只输出 1 个 <action>**。仅当多个动作完全独立、可以并行（如同时读 3 个文件用于对比）时才批处理。串行依赖（读完 A 才知道怎么处理 B）必须分轮。
- 单轮工具数量上限 5 个；超过此数请拆分多轮。
- 严禁用 read_file 读目录路径，用 list_directory

### 模式 B — 直接回答用户

输出结构：
<think>推理过程和最终结论依据</think>
<answer>完整的回答内容（包括具体建议、步骤、代码、分析等所有实质内容）</answer>
<note>简短提醒（≤3句话）</note>

规则：
- 必须包含 <think> + <answer>
- <answer> 必须包含回答的全部实质内容。具体建议、操作步骤、代码片段、详细分析等都属于 answer，不得外溢到 <note>
- <note> 仅用于简短的风险提醒、前提假设或一句话后续方向，严禁超过 3 句话
- 如果没有需要额外提醒的内容，可以省略 <note>
- </answer> 之后只能出现 <note>，不得输出任何其他文字
- 禁止包含 <action>

---

工具执行后你会收到包含 <result> 的回复，解读后继续行动或给出答案。

## 示例

### 简单单步

用户: "读 README.md"
<think>用户想读 README，单步操作</think>
<action tool="read_file">{"filePath": "README.md"}</action>

### 多步任务

用户: "查当前目录有哪些文件，新建 summary.txt 汇总所有文件名"

第 1 回合：
<think>两步任务：先列目录，再写汇总</think>
<action tool="list_directory">{"dirPath": "."}</action>

收到 <result>a.txt, b.txt, README.md</result> 后，第 2 回合：
<think>已获取文件列表，现在写入汇总文件</think>
<action tool="write_file">{"filePath": "summary.txt", "content": "当前目录文件:\\na.txt\\nb.txt\\nREADME.md"}</action>

收到 <result>写入成功</result> 后，第 3 回合：
<think>任务全部完成</think>
<answer>已将 a.txt、b.txt、README.md 汇总写入 summary.txt</answer>
<note>如果后续新增文件，需要重新生成汇总</note>

---

## 常见协议错误（必须避免）

❌ **错误 1：标签外的自然语言**
错误示例：
\`\`\`
<action tool="read_file">{"filePath":"a.txt"}</action>
好的，我已经读完了文件，内容是...   ← 这段裸文本必须包在 <answer> 里！
\`\`\`

❌ **错误 2：在 <action> 后立刻输出结论**
错误示例：
\`\`\`
<action tool="read_file">{"filePath":"a.txt"}</action>
<answer>文件内容是 Hello World</answer>   ← 还没收到 <result>，不许输出 <answer>！
\`\`\`
正确做法：等下一回合收到 <result> 再输出 <answer>。

❌ **错误 3：忘记 <answer> 标签**
错误示例：
\`\`\`
<think>任务完成了</think>
任务已全部完成。   ← 必须用 <answer>...</answer> 包起来！
\`\`\`

## 协议自检清单（每次输出前默念）

- [ ] 我的最终回答是不是包在 <answer>...</answer> 里？
- [ ] <action> 后是否还有未包标签的自然语言？有就拿掉或包进 <answer>。
- [ ] 还在等工具结果时，我是不是不应该输出 <answer>？

## 系统行为告知（了解即可，无需操作）

- 如果你的输出因长度限制被截断（标签未闭合），系统会自动要求你继续输出剩余内容。
- 如果你的回复中既没有 <action> 也没有 <answer>，系统会要求你明确下一步。
- 不要因为担心输出过长而省略关键内容——系统有续写机制保障完整输出。
- 工具调用没有硬性次数上限，复杂任务可以多轮调用直到完成。
- delegate 工具可以连续多次使用：如果一个 SubAgent 汇报"仅完成部分工作"，你可以立即再派一个 SubAgent 接力完成剩余部分。每个 SubAgent 有独立的上下文和工具额度。

## 可用工具

${toolList}
${buildSelfManagementSection()}`;
}
