mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-13 23:36:58 +08:00
refactor: move bundled skills tree to repo root skills/
- Relocate runtime/skills -> skills/; runtime_skills_root() prefers oclaw/skills with fallback to legacy runtime/skills for unmigrated trees. - session-bootstrap hook handler resolves repo root via PROJECT_ROOT. - Update architecture/migration docs and in-tree skill references. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
396dba76ea
commit
beb52006d8
298 changed files with 51 additions and 51 deletions
23
skills/self-improvement/hooks/runtime/HOOK.md
Normal file
23
skills/self-improvement/hooks/runtime/HOOK.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
name: self-improvement
|
||||
description: "在智能体启动阶段注入自我改进提醒"
|
||||
metadata: {"oclaw":{"emoji":"🧠","events":["agent:bootstrap"]}}
|
||||
---
|
||||
|
||||
# 自我改进 Hook
|
||||
|
||||
在 `agent:bootstrap` 阶段注入“学习沉淀提醒”。
|
||||
|
||||
## 功能说明
|
||||
|
||||
- 在 `agent:bootstrap` 触发(工作区文件注入前)
|
||||
- 注入提醒块,引导将学习写入 Wiki 路径
|
||||
- 提示智能体记录纠错、错误与新发现
|
||||
|
||||
## 配置方式
|
||||
|
||||
无需额外配置,启用命令:
|
||||
|
||||
```bash
|
||||
oclaw hooks enable self-improvement
|
||||
```
|
||||
109
skills/self-improvement/hooks/runtime/handler.js
Normal file
109
skills/self-improvement/hooks/runtime/handler.js
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* Oclaw 自我改进 Hook
|
||||
*
|
||||
* 在 agent:bootstrap 阶段注入学习沉淀提醒。
|
||||
*/
|
||||
|
||||
const REMINDER_NAME = 'SELF_IMPROVEMENT_REMINDER.md';
|
||||
const REMINDER_PATH = REMINDER_NAME;
|
||||
|
||||
const REMINDER_CONTENT = `
|
||||
## 自我改进提醒
|
||||
|
||||
任务完成后,请评估是否产生可沉淀学习。
|
||||
|
||||
仅在当前仓库/工作区启用 self-improvement 技能时记录。
|
||||
|
||||
记录前:
|
||||
- 使用 memory_wiki_* 工具写入 \`improvement/\` 下的 Wiki 笔记
|
||||
- 不记录密钥、令牌、私钥、环境变量或原始对话全文
|
||||
- 优先使用简短摘要或脱敏片段,避免完整命令输出
|
||||
|
||||
**以下情况应记录:**
|
||||
- 用户纠正你 → \`improvement/learnings.md\`
|
||||
- 命令/操作失败 → \`improvement/errors.md\`
|
||||
- 用户提出缺失能力 → \`improvement/feature-requests.md\`
|
||||
- 发现认知错误 → \`improvement/learnings.md\`
|
||||
- 发现更优做法 → \`improvement/learnings.md\`
|
||||
|
||||
**当模式被验证后进行提升:**
|
||||
- 行为模式 → \`SOUL.md\`
|
||||
- 工作流改进 → \`AGENTS.md\`
|
||||
- 工具易错点 → \`TOOLS.md\`
|
||||
|
||||
条目保持简洁:时间、标题、发生了什么、后续应如何做。
|
||||
`.trim();
|
||||
|
||||
function isObject(value) {
|
||||
return !!value && typeof value === 'object';
|
||||
}
|
||||
|
||||
function isInjectedReminderFile(value) {
|
||||
if (!isObject(value) || value.path !== REMINDER_PATH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
value.virtual === true ||
|
||||
value.content === REMINDER_CONTENT
|
||||
);
|
||||
}
|
||||
|
||||
const handler = async (event) => {
|
||||
// 事件结构安全检查
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅处理 agent:bootstrap 事件
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// context 安全检查
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳过子代理会话,避免引导污染
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 以虚拟 bootstrap 文件注入提醒
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
const occupiedByOtherFile = event.context.bootstrapFiles.some(
|
||||
(file) => isObject(file) && file.path === REMINDER_PATH && !isInjectedReminderFile(file),
|
||||
);
|
||||
if (occupiedByOtherFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanedBootstrapFiles = event.context.bootstrapFiles.filter(
|
||||
(file, index, files) =>
|
||||
!isInjectedReminderFile(file) ||
|
||||
files.findIndex((candidate) => isInjectedReminderFile(candidate)) === index,
|
||||
);
|
||||
|
||||
const reminderFile = {
|
||||
name: REMINDER_NAME,
|
||||
path: REMINDER_PATH,
|
||||
content: REMINDER_CONTENT,
|
||||
missing: false,
|
||||
virtual: true,
|
||||
};
|
||||
|
||||
const existingIndex = cleanedBootstrapFiles.findIndex((file) => isInjectedReminderFile(file));
|
||||
if (existingIndex === -1) {
|
||||
cleanedBootstrapFiles.push(reminderFile);
|
||||
} else {
|
||||
cleanedBootstrapFiles[existingIndex] = reminderFile;
|
||||
}
|
||||
|
||||
event.context.bootstrapFiles = cleanedBootstrapFiles;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = handler;
|
||||
module.exports.default = handler;
|
||||
85
skills/self-improvement/hooks/runtime/handler.py
Normal file
85
skills/self-improvement/hooks/runtime/handler.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
REMINDER_NAME = "SELF_IMPROVEMENT_REMINDER.md"
|
||||
REMINDER_PATH = REMINDER_NAME
|
||||
|
||||
REMINDER_CONTENT = """## 自我改进提醒
|
||||
|
||||
任务完成后,请评估是否产生可沉淀学习。
|
||||
|
||||
仅在当前仓库/工作区启用 self-improvement 技能时记录。
|
||||
|
||||
记录前:
|
||||
- 使用 memory_wiki_* 工具写入 `improvement/` 下的 Wiki 笔记
|
||||
- 不记录密钥、令牌、私钥、环境变量或原始对话全文
|
||||
- 优先使用简短摘要或脱敏片段,避免完整命令输出
|
||||
|
||||
**以下情况应记录:**
|
||||
- 用户纠正你 → `improvement/learnings.md`
|
||||
- 命令/操作失败 → `improvement/errors.md`
|
||||
- 用户提出缺失能力 → `improvement/feature-requests.md`
|
||||
- 发现认知错误 → `improvement/learnings.md`
|
||||
- 发现更优做法 → `improvement/learnings.md`
|
||||
|
||||
**当模式被验证后进行提升:**
|
||||
- 行为模式 → `SOUL.md`
|
||||
- 工作流改进 → `AGENTS.md`
|
||||
- 工具易错点 → `TOOLS.md`
|
||||
|
||||
条目保持简洁:时间、标题、发生了什么、后续应如何做。"""
|
||||
|
||||
|
||||
def _is_record(value: object) -> bool:
|
||||
return isinstance(value, dict)
|
||||
|
||||
|
||||
def _is_injected_reminder_file(value: object) -> bool:
|
||||
if not _is_record(value) or str(value.get("path")) != REMINDER_PATH: # type: ignore[union-attr]
|
||||
return False
|
||||
v = value # type: ignore[assignment]
|
||||
return v.get("virtual") is True or v.get("content") == REMINDER_CONTENT
|
||||
|
||||
|
||||
def handle(event: object) -> None:
|
||||
if getattr(event, "type", None) != "agent" or getattr(event, "action", None) != "bootstrap":
|
||||
return
|
||||
ctx = getattr(event, "context", None)
|
||||
if not isinstance(ctx, dict):
|
||||
return
|
||||
session_key = str(getattr(event, "sessionKey", "") or "")
|
||||
if ":subagent:" in session_key:
|
||||
return
|
||||
|
||||
if not isinstance(ctx.get("bootstrapFiles"), list):
|
||||
return
|
||||
files: list[object] = list(ctx.get("bootstrapFiles") or [])
|
||||
|
||||
occupied = any(
|
||||
_is_record(f) and str(f.get("path")) == REMINDER_PATH and not _is_injected_reminder_file(f) # type: ignore[union-attr]
|
||||
for f in files
|
||||
)
|
||||
if occupied:
|
||||
return
|
||||
|
||||
cleaned: list[object] = [
|
||||
f
|
||||
for i, f in enumerate(files)
|
||||
if (not _is_injected_reminder_file(f))
|
||||
or (next((j for j, c in enumerate(files) if _is_injected_reminder_file(c)), -1) == i)
|
||||
]
|
||||
|
||||
reminder_file: dict[str, Any] = {
|
||||
"name": REMINDER_NAME,
|
||||
"path": REMINDER_PATH,
|
||||
"content": REMINDER_CONTENT,
|
||||
"missing": False,
|
||||
"virtual": True,
|
||||
}
|
||||
existing_idx = next((i for i, f in enumerate(cleaned) if _is_injected_reminder_file(f)), -1)
|
||||
if existing_idx == -1:
|
||||
cleaned.append(reminder_file)
|
||||
else:
|
||||
cleaned[existing_idx] = reminder_file
|
||||
ctx["bootstrapFiles"] = cleaned
|
||||
108
skills/self-improvement/hooks/runtime/handler.ts
Normal file
108
skills/self-improvement/hooks/runtime/handler.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* Oclaw 自我改进 Hook
|
||||
*
|
||||
* 在 agent:bootstrap 阶段注入学习沉淀提醒。
|
||||
*/
|
||||
|
||||
import type { HookHandler } from 'oclaw/hooks';
|
||||
|
||||
const REMINDER_NAME = 'SELF_IMPROVEMENT_REMINDER.md';
|
||||
const REMINDER_PATH = REMINDER_NAME;
|
||||
|
||||
const REMINDER_CONTENT = `## 自我改进提醒
|
||||
|
||||
任务完成后,请评估是否产生可沉淀学习。
|
||||
|
||||
仅在当前仓库/工作区启用 self-improvement 技能时记录。
|
||||
|
||||
记录前:
|
||||
- 使用 memory_wiki_* 工具写入 \`improvement/\` 下的 Wiki 笔记
|
||||
- 不记录密钥、令牌、私钥、环境变量或原始对话全文
|
||||
- 优先使用简短摘要或脱敏片段,避免完整命令输出
|
||||
|
||||
**以下情况应记录:**
|
||||
- 用户纠正你 → \`improvement/learnings.md\`
|
||||
- 命令/操作失败 → \`improvement/errors.md\`
|
||||
- 用户提出缺失能力 → \`improvement/feature-requests.md\`
|
||||
- 发现认知错误 → \`improvement/learnings.md\`
|
||||
- 发现更优做法 → \`improvement/learnings.md\`
|
||||
|
||||
**当模式被验证后进行提升:**
|
||||
- 行为模式 → \`SOUL.md\`
|
||||
- 工作流改进 → \`AGENTS.md\`
|
||||
- 工具易错点 → \`TOOLS.md\`
|
||||
|
||||
条目保持简洁:时间、标题、发生了什么、后续应如何做。`;
|
||||
|
||||
function isObject(value: unknown): value is Record<string, unknown> {
|
||||
return !!value && typeof value === 'object';
|
||||
}
|
||||
|
||||
function isInjectedReminderFile(value: unknown): boolean {
|
||||
if (!isObject(value) || value.path !== REMINDER_PATH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
value.virtual === true ||
|
||||
value.content === REMINDER_CONTENT
|
||||
);
|
||||
}
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
// 事件结构安全检查
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅处理 agent:bootstrap 事件
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// context 安全检查
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳过子代理会话,避免引导污染
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 以虚拟 bootstrap 文件注入提醒
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
const occupiedByOtherFile = event.context.bootstrapFiles.some(
|
||||
(file) => isObject(file) && file.path === REMINDER_PATH && !isInjectedReminderFile(file),
|
||||
);
|
||||
if (occupiedByOtherFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanedBootstrapFiles = event.context.bootstrapFiles.filter(
|
||||
(file, index, files) =>
|
||||
!isInjectedReminderFile(file) ||
|
||||
files.findIndex((candidate) => isInjectedReminderFile(candidate)) === index,
|
||||
);
|
||||
|
||||
const reminderFile = {
|
||||
name: REMINDER_NAME,
|
||||
path: REMINDER_PATH,
|
||||
content: REMINDER_CONTENT,
|
||||
missing: false,
|
||||
virtual: true,
|
||||
};
|
||||
|
||||
const existingIndex = cleanedBootstrapFiles.findIndex((file) => isInjectedReminderFile(file));
|
||||
if (existingIndex === -1) {
|
||||
cleanedBootstrapFiles.push(reminderFile);
|
||||
} else {
|
||||
cleanedBootstrapFiles[existingIndex] = reminderFile;
|
||||
}
|
||||
|
||||
event.context.bootstrapFiles = cleanedBootstrapFiles;
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
Loading…
Add table
Add a link
Reference in a new issue