From 21e631b6155a01dae0388c643b3f395f8b24bd0d Mon Sep 17 00:00:00 2001 From: zap Date: Thu, 5 Mar 2026 21:08:42 +0000 Subject: [PATCH] feat(hooks): track model-skill-injector in workspace repo --- hooks/model-skill-injector/HOOK.md | 39 +++++++++++++++ hooks/model-skill-injector/handler.ts | 68 +++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 hooks/model-skill-injector/HOOK.md create mode 100644 hooks/model-skill-injector/handler.ts diff --git a/hooks/model-skill-injector/HOOK.md b/hooks/model-skill-injector/HOOK.md new file mode 100644 index 0000000..b456e27 --- /dev/null +++ b/hooks/model-skill-injector/HOOK.md @@ -0,0 +1,39 @@ +--- +name: model-skill-injector +description: "Injects model-specific best-practice context into bootstrap depending on the active LLM (Anthropic vs OpenAI)" +metadata: + { + "openclaw": { + "emoji": "🧠", + "events": ["agent:bootstrap"], + "requires": { "config": ["workspace.dir"] } + } + } +--- + +# model-skill-injector + +Fires on `agent:bootstrap` and appends a model-family-specific best-practices +hint file to the bootstrap context, so the agent always knows which tool-design +rules apply for the currently active model — without bloating the base system +prompt. + +## What it does + +1. Reads the active model string from the event config (`agents.defaults.model.primary`). +2. Detects the model family by model name only: + - **Anthropic** — any model containing `claude` + - **OpenAI** — any model containing `gpt` +3. Injects the corresponding hint file from the workspace `skills/llm-tool-best-practices/` folder as a virtual bootstrap file named `MODEL_HINTS.md`. +4. If the model is unknown / not matched, injects a neutral fallback noting both families. + +## Files + +- Anthropic hints: `skills/llm-tool-best-practices/hints/anthropic.md` +- OpenAI hints: `skills/llm-tool-best-practices/hints/openai.md` +- Fallback: `skills/llm-tool-best-practices/hints/generic.md` + +## Notes + +- Runs read-only; never writes files. +- Only injects the targeted section — does not load the full best-practices doc each turn. diff --git a/hooks/model-skill-injector/handler.ts b/hooks/model-skill-injector/handler.ts new file mode 100644 index 0000000..e90daf3 --- /dev/null +++ b/hooks/model-skill-injector/handler.ts @@ -0,0 +1,68 @@ +import * as fs from "fs"; +import * as path from "path"; + +const handler = async (event) => { + if (event.type !== "agent" || event.action !== "bootstrap") return; + + const cfg = event.context?.cfg; + const workspaceDir = event.context?.workspaceDir; + if (!workspaceDir) return; + + // Resolve active model string + const modelRaw: string = + (typeof cfg?.agents?.defaults?.model === "string" + ? cfg.agents.defaults.model + : cfg?.agents?.defaults?.model?.primary) ?? ""; + + const model = modelRaw.toLowerCase(); + + // Detect model family by model name (provider-agnostic) + let family: "anthropic" | "openai" | "generic"; + if (model.includes("claude")) { + family = "anthropic"; + } else if (model.includes("gpt")) { + family = "openai"; + } else { + family = "generic"; + } + + const hintsDir = path.join( + workspaceDir, + "skills", + "llm-tool-best-practices", + "hints" + ); + const hintsFile = path.join(hintsDir, `${family}.md`); + + let content: string; + try { + content = fs.readFileSync(hintsFile, "utf8"); + } catch { + // Hints file missing — skip silently + console.warn( + `[model-skill-injector] Hints file not found: ${hintsFile} (family=${family}, model=${modelRaw})` + ); + return; + } + + // Inject as a virtual bootstrap file + const bootstrapFiles = event.context?.bootstrapFiles; + if (!Array.isArray(bootstrapFiles)) return; + + // Remove any previous injection (idempotent on re-runs) + const existing = bootstrapFiles.findIndex((f) => f.name === "MODEL_HINTS.md"); + if (existing !== -1) bootstrapFiles.splice(existing, 1); + + bootstrapFiles.push({ + name: "MODEL_HINTS.md", + content, + // Mark virtual so it doesn't try to read from disk + virtual: true, + }); + + console.log( + `[model-skill-injector] Injected ${family} hints (model=${modelRaw})` + ); +}; + +export default handler;