ofiere-openclaw-plugin 4.34.0 → 4.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/prompt.ts +10 -0
- package/src/tools.ts +190 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofiere-openclaw-plugin",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.35.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw plugin for Ofiere PM - 14 meta-tools covering tasks, agents, projects, scheduling, knowledge, workflows, notifications, memory, prompts, constellation, space file management, execution plan builder, SOP management, and agent brain (memory + self-improvement)",
|
|
6
6
|
"keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
|
package/src/prompt.ts
CHANGED
|
@@ -26,6 +26,7 @@ const TOOL_SUMMARIES: Record<string, string> = {
|
|
|
26
26
|
OFIERE_PLAN_OPS: "Visual execution plan builder (DAG drafts → real tasks)",
|
|
27
27
|
OFIERE_SOP_OPS: "Standard Operating Procedures for department chiefs",
|
|
28
28
|
OFIERE_BRAIN_OPS: "Agent memory, knowledge graph, self-improvement (TMT/MAGMA)",
|
|
29
|
+
OFIERE_TALENT_OPS: "Talents: list, get, activate, deactivate cognitive skill presets",
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
// ─── Tier B: Full Tool Documentation ────────────────────────────────────────
|
|
@@ -113,6 +114,15 @@ Actions: "list_templates", "create", "list", "get", "update", "delete", "list_su
|
|
|
113
114
|
Memory Tiers: L1_focus (24h), L2_episode (days), L3_pattern (weeks), L4_rule (permanent), L5_persona (permanent)
|
|
114
115
|
Actions: save_memory, recall, delete_memory, promote_memory, log_learning, list_learnings, resolve_learning, save_entity, link_entities, query_graph, start_trajectory, end_trajectory, get_brain_status
|
|
115
116
|
- This is your SUBCONSCIOUS — use instinctively, not deliberately`,
|
|
117
|
+
|
|
118
|
+
OFIERE_TALENT_OPS: `Manage cognitive skill presets (Talents).
|
|
119
|
+
Actions: "list", "get", "activate", "deactivate"
|
|
120
|
+
- list: List all talents. Optional: category, scope, status
|
|
121
|
+
- get: Get full talent details. Required: talent_id OR name
|
|
122
|
+
- activate: Enable a talent (status → active). Required: talent_id
|
|
123
|
+
- deactivate: Disable a talent (status → inactive). Required: talent_id
|
|
124
|
+
- Active talents inject their execution_protocol and guardrails into your system prompt automatically
|
|
125
|
+
- Talents chain other tools: SPHINX chains KNOWLEDGE_OPS+BRAIN_OPS, PRISM chains BRAIN_OPS trajectories, ATLAS chains PLAN_OPS+TASK_OPS+SOP_OPS`,
|
|
116
126
|
};
|
|
117
127
|
|
|
118
128
|
export function getSystemPrompt(state: {
|
package/src/tools.ts
CHANGED
|
@@ -5632,6 +5632,191 @@ function registerBrainOps(
|
|
|
5632
5632
|
}));
|
|
5633
5633
|
}
|
|
5634
5634
|
|
|
5635
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5636
|
+
// TALENT OPS — Cognitive Skill Presets (list / get / activate / deactivate)
|
|
5637
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5638
|
+
|
|
5639
|
+
function registerTalentOps(
|
|
5640
|
+
api: any, supabase: SupabaseClient, userId: string,
|
|
5641
|
+
) {
|
|
5642
|
+
api.registerTool(api.createToolDefinition({
|
|
5643
|
+
name: "OFIERE_TALENT_OPS",
|
|
5644
|
+
label: "Ofiere Talent Operations",
|
|
5645
|
+
description:
|
|
5646
|
+
`Manage cognitive skill presets (Talents).\n` +
|
|
5647
|
+
`Actions: "list", "get", "activate", "deactivate"\n` +
|
|
5648
|
+
`- list: List all talents. Optional: category, scope, status\n` +
|
|
5649
|
+
`- get: Get full talent details. Required: talent_id OR name\n` +
|
|
5650
|
+
`- activate: Enable a talent (status → active). Required: talent_id\n` +
|
|
5651
|
+
`- deactivate: Disable a talent (status → inactive). Required: talent_id\n` +
|
|
5652
|
+
`- Active talents inject their execution_protocol and guardrails into your system prompt automatically\n` +
|
|
5653
|
+
`- Talents chain other tools: SPHINX chains KNOWLEDGE_OPS+BRAIN_OPS, PRISM chains BRAIN_OPS trajectories, ATLAS chains PLAN_OPS+TASK_OPS+SOP_OPS`,
|
|
5654
|
+
parameters: {
|
|
5655
|
+
type: "object",
|
|
5656
|
+
required: ["action"],
|
|
5657
|
+
properties: {
|
|
5658
|
+
action: { type: "string", description: "list, get, activate, deactivate" },
|
|
5659
|
+
talent_id: { type: "string", description: "Talent UUID" },
|
|
5660
|
+
name: { type: "string", description: "Talent name (for get by name)" },
|
|
5661
|
+
category: { type: "string", description: "Filter: research, analysis, operations, general" },
|
|
5662
|
+
scope: { type: "string", description: "Filter: global, agent_specific" },
|
|
5663
|
+
status: { type: "string", description: "Filter: active, inactive" },
|
|
5664
|
+
},
|
|
5665
|
+
},
|
|
5666
|
+
async execute(_id: string, params: Record<string, unknown>) {
|
|
5667
|
+
const action = params.action as string;
|
|
5668
|
+
try {
|
|
5669
|
+
switch (action) {
|
|
5670
|
+
case "list": {
|
|
5671
|
+
let q = supabase.from("ofiere_talents")
|
|
5672
|
+
.select("id, name, codename, description, category, icon, scope, status, tags, version")
|
|
5673
|
+
.eq("user_id", userId)
|
|
5674
|
+
.order("created_at", { ascending: false });
|
|
5675
|
+
if (params.category) q = q.eq("category", params.category as string);
|
|
5676
|
+
if (params.scope) q = q.eq("scope", params.scope as string);
|
|
5677
|
+
if (params.status) q = q.eq("status", params.status as string);
|
|
5678
|
+
const { data, error } = await q.limit(50);
|
|
5679
|
+
if (error) return { success: false, result: error.message };
|
|
5680
|
+
return { success: true, result: { talents: data || [], count: data?.length || 0 } };
|
|
5681
|
+
}
|
|
5682
|
+
case "get": {
|
|
5683
|
+
const tid = params.talent_id as string;
|
|
5684
|
+
const tname = params.name as string;
|
|
5685
|
+
if (!tid && !tname) return { success: false, result: "Required: talent_id or name" };
|
|
5686
|
+
let q = supabase.from("ofiere_talents").select("*").eq("user_id", userId);
|
|
5687
|
+
if (tid) q = q.eq("id", tid);
|
|
5688
|
+
else q = q.ilike("name", `%${tname}%`);
|
|
5689
|
+
const { data, error } = await q.limit(1).maybeSingle();
|
|
5690
|
+
if (error) return { success: false, result: error.message };
|
|
5691
|
+
if (!data) return { success: false, result: "Talent not found" };
|
|
5692
|
+
return { success: true, result: data };
|
|
5693
|
+
}
|
|
5694
|
+
case "activate": {
|
|
5695
|
+
const tid = params.talent_id as string;
|
|
5696
|
+
if (!tid) return { success: false, result: "Required: talent_id" };
|
|
5697
|
+
const { error } = await supabase.from("ofiere_talents")
|
|
5698
|
+
.update({ status: "active", updated_at: new Date().toISOString() })
|
|
5699
|
+
.eq("id", tid).eq("user_id", userId);
|
|
5700
|
+
if (error) return { success: false, result: error.message };
|
|
5701
|
+
return { success: true, result: { message: "Talent activated", talent_id: tid } };
|
|
5702
|
+
}
|
|
5703
|
+
case "deactivate": {
|
|
5704
|
+
const tid = params.talent_id as string;
|
|
5705
|
+
if (!tid) return { success: false, result: "Required: talent_id" };
|
|
5706
|
+
const { error } = await supabase.from("ofiere_talents")
|
|
5707
|
+
.update({ status: "inactive", updated_at: new Date().toISOString() })
|
|
5708
|
+
.eq("id", tid).eq("user_id", userId);
|
|
5709
|
+
if (error) return { success: false, result: error.message };
|
|
5710
|
+
return { success: true, result: { message: "Talent deactivated", talent_id: tid } };
|
|
5711
|
+
}
|
|
5712
|
+
default:
|
|
5713
|
+
return { success: false, result: `Unknown action: ${action}. Valid: list, get, activate, deactivate` };
|
|
5714
|
+
}
|
|
5715
|
+
} catch (e) {
|
|
5716
|
+
return { success: false, result: e instanceof Error ? e.message : String(e) };
|
|
5717
|
+
}
|
|
5718
|
+
},
|
|
5719
|
+
}));
|
|
5720
|
+
}
|
|
5721
|
+
|
|
5722
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5723
|
+
// TALENT CONTEXT HOOK — Injects active talent protocols into system prompt
|
|
5724
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5725
|
+
// This is the engine that makes talents WORK. Without this hook, talents are
|
|
5726
|
+
// just database rows. The hook turns them into cognitive directives injected
|
|
5727
|
+
// before every agent turn via appendSystemContext.
|
|
5728
|
+
|
|
5729
|
+
const talentCache = new Map<string, { text: string; at: number }>();
|
|
5730
|
+
const TALENT_CACHE_TTL = 300_000; // 5 min
|
|
5731
|
+
|
|
5732
|
+
function registerTalentContextHook(
|
|
5733
|
+
api: any, supabase: SupabaseClient, userId: string, fallbackAgentId: string,
|
|
5734
|
+
) {
|
|
5735
|
+
try {
|
|
5736
|
+
api.on("before_prompt_build", async (_event: any, ctx: any) => {
|
|
5737
|
+
try {
|
|
5738
|
+
const ctxAgentId = ctx?.agentId || "";
|
|
5739
|
+
let resolvedAgentId = fallbackAgentId;
|
|
5740
|
+
if (ctxAgentId && !isSystemName(ctxAgentId)) {
|
|
5741
|
+
try {
|
|
5742
|
+
const resolved = await resolveAgentId(ctxAgentId, userId, supabase);
|
|
5743
|
+
if (resolved) resolvedAgentId = resolved;
|
|
5744
|
+
} catch { /* fallback */ }
|
|
5745
|
+
}
|
|
5746
|
+
|
|
5747
|
+
const cacheKey = `talent:${resolvedAgentId || "global"}`;
|
|
5748
|
+
const cached = talentCache.get(cacheKey);
|
|
5749
|
+
if (cached && (Date.now() - cached.at) < TALENT_CACHE_TTL) {
|
|
5750
|
+
return cached.text ? { appendSystemContext: cached.text } : undefined;
|
|
5751
|
+
}
|
|
5752
|
+
|
|
5753
|
+
// Query active talents: global OR assigned to this agent
|
|
5754
|
+
const { data: talents } = await supabase
|
|
5755
|
+
.from("ofiere_talents")
|
|
5756
|
+
.select("name, codename, execution_protocol, guardrails, trigger_conditions, config")
|
|
5757
|
+
.eq("user_id", userId)
|
|
5758
|
+
.eq("status", "active")
|
|
5759
|
+
.order("created_at", { ascending: true });
|
|
5760
|
+
|
|
5761
|
+
if (!talents || talents.length === 0) {
|
|
5762
|
+
talentCache.set(cacheKey, { text: "", at: Date.now() });
|
|
5763
|
+
return;
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5766
|
+
// Filter: global talents + agent-specific talents assigned to this agent
|
|
5767
|
+
// (assigned_agent_ids check is done client-side since JSONB contains is complex)
|
|
5768
|
+
const sections: string[] = [];
|
|
5769
|
+
for (const t of talents) {
|
|
5770
|
+
const ep = t.execution_protocol || [];
|
|
5771
|
+
const gr = t.guardrails || {};
|
|
5772
|
+
const tc = t.trigger_conditions || {};
|
|
5773
|
+
|
|
5774
|
+
let block = `### 🎯 Talent: ${t.name} (${t.codename || "custom"})`;
|
|
5775
|
+
|
|
5776
|
+
// Triggers
|
|
5777
|
+
const triggers = [
|
|
5778
|
+
...(tc.keywords || []),
|
|
5779
|
+
...(tc.explicit_commands || []),
|
|
5780
|
+
];
|
|
5781
|
+
if (triggers.length > 0) {
|
|
5782
|
+
block += `\nTriggers: ${triggers.join(", ")}`;
|
|
5783
|
+
}
|
|
5784
|
+
|
|
5785
|
+
// Execution Protocol (compact)
|
|
5786
|
+
if (ep.length > 0) {
|
|
5787
|
+
block += "\nExecution Protocol:";
|
|
5788
|
+
for (let i = 0; i < ep.length; i++) {
|
|
5789
|
+
const step = ep[i] as any;
|
|
5790
|
+
block += `\n${i + 1}. **${step.phase}**: ${step.instruction}`;
|
|
5791
|
+
if (step.checkpoint) block += `\n ✓ Checkpoint: ${step.checkpoint}`;
|
|
5792
|
+
}
|
|
5793
|
+
}
|
|
5794
|
+
|
|
5795
|
+
// Guardrails (compact)
|
|
5796
|
+
const mustNever = gr.must_never || [];
|
|
5797
|
+
const hardConstraints = gr.hard_constraints || [];
|
|
5798
|
+
if (mustNever.length > 0 || hardConstraints.length > 0) {
|
|
5799
|
+
block += "\n⚠️ Guardrails:";
|
|
5800
|
+
for (const mn of mustNever) block += `\n- 🚫 NEVER: ${mn}`;
|
|
5801
|
+
for (const hc of hardConstraints) block += `\n- ⛔ CONSTRAINT: ${hc}`;
|
|
5802
|
+
}
|
|
5803
|
+
|
|
5804
|
+
sections.push(block);
|
|
5805
|
+
}
|
|
5806
|
+
|
|
5807
|
+
const talentContext = `<agent-talents>\n## Your Active Talents (${talents.length})\n\nThese are cognitive skill presets that define HOW you should approach specific types of tasks.\nWhen a user request matches a talent's triggers, follow that talent's execution protocol.\n\n${sections.join("\n\n---\n\n")}\n</agent-talents>`;
|
|
5808
|
+
|
|
5809
|
+
talentCache.set(cacheKey, { text: talentContext, at: Date.now() });
|
|
5810
|
+
return { appendSystemContext: talentContext };
|
|
5811
|
+
} catch (e) {
|
|
5812
|
+
api.logger.debug?.(`[ofiere-talent] before_prompt_build error: ${e instanceof Error ? e.message : e}`);
|
|
5813
|
+
}
|
|
5814
|
+
});
|
|
5815
|
+
} catch {
|
|
5816
|
+
api.logger.debug?.("[ofiere] Could not register talent context hook");
|
|
5817
|
+
}
|
|
5818
|
+
}
|
|
5819
|
+
|
|
5635
5820
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5636
5821
|
// Public: Register All Meta-Tools
|
|
5637
5822
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -5663,22 +5848,19 @@ export function registerTools(
|
|
|
5663
5848
|
registerPlanOps(api, supabase, userId, resolveAgent); // 12
|
|
5664
5849
|
registerSOPOps(api, supabase, userId, resolveAgent); // 13
|
|
5665
5850
|
registerBrainOps(api, supabase, userId, resolveAgent); // 14
|
|
5851
|
+
registerTalentOps(api, supabase, userId); // 15
|
|
5666
5852
|
|
|
5667
5853
|
// ── Register dynamic brain context hook ──
|
|
5668
|
-
// FIX (v4.30.0): Was injectBrainContext() which loaded once at registration.
|
|
5669
|
-
// Now registers a before_prompt_build hook that dynamically resolves the
|
|
5670
|
-
// calling agent from ctx.agentId and loads THAT agent's brain memories.
|
|
5671
|
-
// Each agent sees its own brain context — Daisy sees Daisy's, Ivy sees Ivy's.
|
|
5672
5854
|
registerBrainContextHook(api, supabase, userId, fallbackAgentId);
|
|
5673
5855
|
|
|
5856
|
+
// ── Register talent context hook ──
|
|
5857
|
+
registerTalentContextHook(api, supabase, userId, fallbackAgentId);
|
|
5858
|
+
|
|
5674
5859
|
// ── Register agent_end hook for server-side brain extraction ──
|
|
5675
|
-
// This is the FIX for Bug 2: extraction was client-side only (useSocket.ts).
|
|
5676
|
-
// Now every completed agent turn — from ANY channel (Telegram, Discord,
|
|
5677
|
-
// webchat, scheduled) — triggers memory extraction server-side.
|
|
5678
5860
|
registerBrainExtractionHook(api, supabase, userId, fallbackAgentId);
|
|
5679
5861
|
|
|
5680
5862
|
// ── Count and log ──
|
|
5681
|
-
const toolCount =
|
|
5863
|
+
const toolCount = 15;
|
|
5682
5864
|
const callerName = getCallingAgentName(api);
|
|
5683
5865
|
const agentLabel = fallbackAgentId || callerName || "auto-detect";
|
|
5684
5866
|
api.logger.info(`[ofiere] ${toolCount} meta-tools registered (agent: ${agentLabel})`);
|