ofiere-openclaw-plugin 4.40.0 → 4.41.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/agent-tier.ts +30 -0
- package/src/attachments.ts +20 -9
- package/src/prompt.ts +9 -3
- package/src/tools.ts +52 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofiere-openclaw-plugin",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.41.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw plugin for Ofiere PM - 16 meta-tools covering tasks, agents, projects, scheduling, knowledge, workflows, notifications, memory, prompts, constellation, space file management, execution plan builder, SOP management, agent brain, talent management, and corporate frameworks",
|
|
6
6
|
"keywords": ["openclaw", "ofiere", "project-management", "agents", "plugin"],
|
package/src/agent-tier.ts
CHANGED
|
@@ -134,6 +134,36 @@ export async function getAgentTier(
|
|
|
134
134
|
return (await resolveAgentTier(supabase, agentId, userId)).tier;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
// Target-aware resolution: when a work target carries a subagent_id, the
|
|
138
|
+
// work is staff-tier regardless of which chief routes it. Uncached lookup —
|
|
139
|
+
// subagent rows can be deleted out from under us.
|
|
140
|
+
export interface TargetTierInput {
|
|
141
|
+
agentId: string | null;
|
|
142
|
+
subagentId?: string | null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function resolveTargetTier(
|
|
146
|
+
supabase: SupabaseClient,
|
|
147
|
+
target: TargetTierInput,
|
|
148
|
+
userId: string,
|
|
149
|
+
): Promise<TierResolution> {
|
|
150
|
+
if (target.subagentId) {
|
|
151
|
+
try {
|
|
152
|
+
const { data } = await supabase
|
|
153
|
+
.from("agent_subagents")
|
|
154
|
+
.select("id")
|
|
155
|
+
.eq("user_id", userId)
|
|
156
|
+
.eq("id", target.subagentId)
|
|
157
|
+
.maybeSingle();
|
|
158
|
+
if (data?.id) return { tier: "staff", source: "subagent" };
|
|
159
|
+
} catch {
|
|
160
|
+
// Fall through to chief lookup
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (target.agentId) return resolveAgentTier(supabase, target.agentId, userId);
|
|
164
|
+
return { tier: null, source: "none" };
|
|
165
|
+
}
|
|
166
|
+
|
|
137
167
|
export function isDocKindValidForTier(
|
|
138
168
|
docKind: "sop" | "framework",
|
|
139
169
|
tier: AgentTier,
|
package/src/attachments.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
11
11
|
import { renderAttachmentBlock } from "./sop-render.js";
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
resolveTargetTier,
|
|
14
14
|
isDocKindValidForTier,
|
|
15
15
|
invalidateAgentTier,
|
|
16
16
|
} from "./agent-tier.js";
|
|
@@ -99,24 +99,33 @@ async function applyAttachmentWrite(args: {
|
|
|
99
99
|
return { ok: false, error: "unsupported target_kind" };
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
// ── Load target row (
|
|
103
|
-
|
|
102
|
+
// ── Load target row identity (chief agent + optional subagent) for tier check ──
|
|
103
|
+
interface TargetIdentity {
|
|
104
|
+
agentId: string | null;
|
|
105
|
+
subagentId: string | null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function loadTargetIdentity(args: {
|
|
104
109
|
supabase: SupabaseClient;
|
|
105
110
|
userId: string;
|
|
106
111
|
targetKind: TargetKind;
|
|
107
112
|
targetId: string;
|
|
108
|
-
}): Promise<
|
|
113
|
+
}): Promise<TargetIdentity | null> {
|
|
109
114
|
const { supabase, userId, targetKind, targetId } = args;
|
|
110
115
|
const tbl =
|
|
111
116
|
targetKind === "conversation" ? "conversations" :
|
|
112
117
|
targetKind === "task" ? "tasks" : "scheduler_events";
|
|
113
118
|
const { data } = await supabase
|
|
114
119
|
.from(tbl)
|
|
115
|
-
.select("agent_id")
|
|
120
|
+
.select("agent_id, subagent_id")
|
|
116
121
|
.eq("user_id", userId)
|
|
117
122
|
.eq("id", targetId)
|
|
118
123
|
.maybeSingle();
|
|
119
|
-
|
|
124
|
+
if (!data) return null;
|
|
125
|
+
return {
|
|
126
|
+
agentId: (data.agent_id as string | null) ?? null,
|
|
127
|
+
subagentId: (data.subagent_id as string | null) ?? null,
|
|
128
|
+
};
|
|
120
129
|
}
|
|
121
130
|
|
|
122
131
|
// ── Validate that every doc id belongs to userId in the right table ──
|
|
@@ -159,12 +168,14 @@ export async function handleProposeAttach(args: {
|
|
|
159
168
|
(x): x is string => typeof x === "string",
|
|
160
169
|
);
|
|
161
170
|
|
|
162
|
-
const
|
|
171
|
+
const identity = await loadTargetIdentity({
|
|
163
172
|
supabase, userId, targetKind, targetId,
|
|
164
173
|
});
|
|
165
|
-
if (!
|
|
174
|
+
if (!identity || (!identity.agentId && !identity.subagentId)) {
|
|
175
|
+
return err("target_not_found_or_no_agent");
|
|
176
|
+
}
|
|
166
177
|
|
|
167
|
-
const tierResolution = await
|
|
178
|
+
const tierResolution = await resolveTargetTier(supabase, identity, userId);
|
|
168
179
|
if (!tierResolution.tier) {
|
|
169
180
|
return err("agent_unclassified — set tier in dashboard agent settings or via override");
|
|
170
181
|
}
|
package/src/prompt.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const TOOL_SUMMARIES: Record<string, string> = {
|
|
15
15
|
OFIERE_TASK_OPS: "Manage tasks: list, create, update, delete, approvals",
|
|
16
|
-
OFIERE_AGENT_OPS: "Query
|
|
16
|
+
OFIERE_AGENT_OPS: "Query + manage agents and their staff subagents",
|
|
17
17
|
OFIERE_PROJECT_OPS: "PM hierarchy: spaces, folders, dependencies",
|
|
18
18
|
OFIERE_SCHEDULE_OPS: "Calendar: list, create, update, delete events",
|
|
19
19
|
OFIERE_KNOWLEDGE_OPS: "Knowledge library: search, list, create, update, delete",
|
|
@@ -48,7 +48,13 @@ Actions: "list", "create", "update", "delete", "add_approval", "list_approvals",
|
|
|
48
48
|
- list_approvals: List approvals. Optional: task_id, approval_status (pending|approved|rejected)
|
|
49
49
|
- resolve_approval: Approve/reject. Requires: approval_id, approval_status. Optional: comment`,
|
|
50
50
|
|
|
51
|
-
OFIERE_AGENT_OPS: `Query
|
|
51
|
+
OFIERE_AGENT_OPS: `Query + manage agents and their staff subagents.
|
|
52
|
+
Actions: "list", "list_subagents", "create_subagent", "delete_subagent", "invalidate_tier_cache"
|
|
53
|
+
- list: All top-level agents (chiefs / native + OpenClaw) with IDs, names, roles. Use for task assignment lookup.
|
|
54
|
+
- list_subagents: Staff under a chief. Required: chief_agent_id.
|
|
55
|
+
- create_subagent: Add a staff subagent under a chief (max 5 per chief). Required: chief_agent_id, name. Optional: role (default "Staff"), codename, color_hex.
|
|
56
|
+
- delete_subagent: Remove a staff subagent. Required: subagent_id.
|
|
57
|
+
- invalidate_tier_cache: Flush plugin's in-process tier cache (5 min TTL). Optional: agent_id. Use after direct-DB mutation of agent_tier_overrides.`,
|
|
52
58
|
|
|
53
59
|
OFIERE_PROJECT_OPS: `Manage PM hierarchy.
|
|
54
60
|
Actions: "list_spaces", "create_space", "update_space", "delete_space", "list_folders", "create_folder", "update_folder", "delete_folder", "list_dependencies", "add_dependency", "remove_dependency"
|
|
@@ -107,7 +113,7 @@ Actions: "list", "get", "create", "update", "delete", "add_nodes", "execute"
|
|
|
107
113
|
- Execution maps ALL fields: execution_steps, goals, constraints, system_prompt`,
|
|
108
114
|
|
|
109
115
|
OFIERE_SOP_OPS: `Standard Operating Procedures.
|
|
110
|
-
Actions: "list_templates", "create", "list", "get", "update", "delete", "list_subagents", "
|
|
116
|
+
Actions: "list_templates", "create", "list", "get", "update", "delete", "list_subagents", "apply_template", "propose_attach", "commit_attach"
|
|
111
117
|
- sop_data: { title, purpose, scope, applicability, prerequisites:{ conditions, required_tools, required_permissions, safety_warnings }, procedure_steps[], expected_outputs[], escalation_rules[], acceptance_criteria[], rollback_procedure, notes }
|
|
112
118
|
- Legacy field names still accepted (objective→purpose, steps→procedure_steps, deliverables→expected_outputs, escalationRules→escalation_rules, successCriteria→acceptance_criteria) — prefer new names.
|
|
113
119
|
- propose_attach / commit_attach: attach SOPs to a run (target_kind: conversation|task|scheduler_event). Tier rule: SOPs only attach to STAFF-tier targets; for c-suite use OFIERE_FRAMEWORK_OPS instead. propose_attach returns a token-cost summary + confirmation_token (5-min ttl). You MUST surface the cost and ask the user before calling commit_attach. The user must explicitly approve.
|
package/src/tools.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
handleCommitAttach,
|
|
19
19
|
registerAttachmentContextHook,
|
|
20
20
|
} from "./attachments.js";
|
|
21
|
+
import { invalidateAgentTier } from "./agent-tier.js";
|
|
21
22
|
|
|
22
23
|
// ─── Tool result shape (matches OpenClaw SDK) ────────────────────────────────
|
|
23
24
|
|
|
@@ -1088,9 +1089,13 @@ function registerAgentOps(
|
|
|
1088
1089
|
name: "OFIERE_AGENT_OPS",
|
|
1089
1090
|
label: "Ofiere Agent Operations",
|
|
1090
1091
|
description:
|
|
1091
|
-
`Query agents in the Ofiere PM system.\n\n` +
|
|
1092
|
+
`Query and manage agents + their staff subagents in the Ofiere PM system.\n\n` +
|
|
1092
1093
|
`Actions:\n` +
|
|
1093
|
-
`- "list": List all
|
|
1094
|
+
`- "list": List all top-level agents (chiefs / native + OpenClaw) with their IDs, names, roles, and status. Use this to find the correct agent_id for task assignment.\n` +
|
|
1095
|
+
`- "list_subagents": List staff subagents under a chief. Required: chief_agent_id.\n` +
|
|
1096
|
+
`- "create_subagent": Create a staff subagent under a chief (max 5 per chief). Required: chief_agent_id, name. Optional: role (default "Staff"), codename, color_hex (default "#64748b").\n` +
|
|
1097
|
+
`- "delete_subagent": Remove a staff subagent. Required: subagent_id.\n` +
|
|
1098
|
+
`- "invalidate_tier_cache": Flush the plugin's in-process tier resolver cache (5 min TTL). Optional: agent_id to flush a single entry; omit to flush all entries for the calling user. Use after any direct-DB mutation of agent_tier_overrides.`,
|
|
1094
1099
|
parameters: {
|
|
1095
1100
|
type: "object",
|
|
1096
1101
|
required: ["action"],
|
|
@@ -1098,8 +1103,15 @@ function registerAgentOps(
|
|
|
1098
1103
|
action: {
|
|
1099
1104
|
type: "string",
|
|
1100
1105
|
description: "The operation to perform",
|
|
1101
|
-
enum: ["list"],
|
|
1106
|
+
enum: ["list", "list_subagents", "create_subagent", "delete_subagent", "invalidate_tier_cache"],
|
|
1102
1107
|
},
|
|
1108
|
+
chief_agent_id: { type: "string", description: "Chief agent ID (required for list_subagents, create_subagent)" },
|
|
1109
|
+
subagent_id: { type: "string", description: "Subagent ID (required for delete_subagent)" },
|
|
1110
|
+
agent_id: { type: "string", description: "Agent ID (optional for invalidate_tier_cache — omit to flush all entries for the user)" },
|
|
1111
|
+
name: { type: "string", description: "Subagent display name (required for create_subagent)" },
|
|
1112
|
+
role: { type: "string", description: "Subagent role label, e.g. 'Staff', 'Analyst'. Defaults to 'Staff'." },
|
|
1113
|
+
codename: { type: "string", description: "Optional subagent codename" },
|
|
1114
|
+
color_hex: { type: "string", description: "Optional subagent UI color, default '#64748b'" },
|
|
1103
1115
|
},
|
|
1104
1116
|
},
|
|
1105
1117
|
async execute(_id: string, params: Record<string, unknown>) {
|
|
@@ -1108,13 +1120,35 @@ function registerAgentOps(
|
|
|
1108
1120
|
switch (action) {
|
|
1109
1121
|
case "list":
|
|
1110
1122
|
return handleListAgents(api, supabase, userId, fallbackAgentId);
|
|
1123
|
+
case "list_subagents":
|
|
1124
|
+
return handleListSubagents(supabase, userId, params);
|
|
1125
|
+
case "create_subagent":
|
|
1126
|
+
return handleCreateSubagent(supabase, userId, params);
|
|
1127
|
+
case "delete_subagent":
|
|
1128
|
+
return handleDeleteSubagent(supabase, userId, params);
|
|
1129
|
+
case "invalidate_tier_cache":
|
|
1130
|
+
return handleInvalidateTierCache(userId, params);
|
|
1111
1131
|
default:
|
|
1112
|
-
return err(`Unknown action "${action}". Valid actions: list`);
|
|
1132
|
+
return err(`Unknown action "${action}". Valid actions: list, list_subagents, create_subagent, delete_subagent, invalidate_tier_cache`);
|
|
1113
1133
|
}
|
|
1114
1134
|
},
|
|
1115
1135
|
});
|
|
1116
1136
|
}
|
|
1117
1137
|
|
|
1138
|
+
function handleInvalidateTierCache(userId: string, params: Record<string, unknown>): ToolResult {
|
|
1139
|
+
const agentId = params.agent_id as string | undefined;
|
|
1140
|
+
invalidateAgentTier(userId, agentId);
|
|
1141
|
+
return ok({
|
|
1142
|
+
ok: true,
|
|
1143
|
+
scope: agentId ? "single" : "user",
|
|
1144
|
+
user_id: userId,
|
|
1145
|
+
agent_id: agentId ?? null,
|
|
1146
|
+
message: agentId
|
|
1147
|
+
? `Plugin tier cache flushed for agent ${agentId}.`
|
|
1148
|
+
: `Plugin tier cache flushed for all entries belonging to user ${userId}.`,
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1118
1152
|
async function handleListAgents(
|
|
1119
1153
|
api: any,
|
|
1120
1154
|
supabase: SupabaseClient,
|
|
@@ -4847,9 +4881,7 @@ function registerSOPOps(
|
|
|
4847
4881
|
`- "get": Get full SOP details. Required: sop_id\n` +
|
|
4848
4882
|
`- "update": Modify SOP. Required: sop_id. Optional: title, sop_data, status, department\n` +
|
|
4849
4883
|
`- "delete": Remove SOP. Required: sop_id\n` +
|
|
4850
|
-
`- "list_subagents": List subagents for a chief. Required: chief_agent_id\n` +
|
|
4851
|
-
`- "create_subagent": Create a staff subagent under a chief (max 5 per chief). Required: chief_agent_id, name. Optional: role (default "Staff"), codename, color_hex (default "#64748b").\n` +
|
|
4852
|
-
`- "delete_subagent": Delete a staff subagent. Required: subagent_id\n` +
|
|
4884
|
+
`- "list_subagents": List subagents for a chief. Required: chief_agent_id. (Provided here for convenience when scoping SOP authoring; team management lives in OFIERE_AGENT_OPS.)\n` +
|
|
4853
4885
|
`- "apply_template": Create SOP from template. Required: agent_id, template_id. Optional: title, department\n` +
|
|
4854
4886
|
`- "propose_attach": Propose attaching SOPs to a run target (conversation/task/scheduler_event). Returns token cost + confirmation_token. Required: target_kind, target_id, doc_ids[]. The user MUST be asked to approve before commit.\n` +
|
|
4855
4887
|
`- "commit_attach": Commit a proposed attachment. Required: target_kind, target_id, doc_ids[], confirmation_token (from propose_attach). Only call AFTER user approves the token cost.\n` +
|
|
@@ -4873,15 +4905,10 @@ function registerSOPOps(
|
|
|
4873
4905
|
type: "object",
|
|
4874
4906
|
required: ["action"],
|
|
4875
4907
|
properties: {
|
|
4876
|
-
action: { type: "string", enum: ["list_templates", "create", "list", "get", "update", "delete", "list_subagents", "
|
|
4908
|
+
action: { type: "string", enum: ["list_templates", "create", "list", "get", "update", "delete", "list_subagents", "apply_template", "propose_attach", "commit_attach"], description: "Valid actions: list_templates, create, list, get, update, delete, list_subagents, apply_template, propose_attach, commit_attach" },
|
|
4877
4909
|
sop_id: { type: "string", description: "SOP ID (required for get, update, delete)" },
|
|
4878
4910
|
agent_id: { type: "string", description: "Agent ID (required for create, list filter, apply_template)" },
|
|
4879
|
-
chief_agent_id: { type: "string", description: "Chief agent ID (required for list_subagents
|
|
4880
|
-
subagent_id: { type: "string", description: "Subagent ID (required for delete_subagent)" },
|
|
4881
|
-
name: { type: "string", description: "Subagent display name (required for create_subagent)" },
|
|
4882
|
-
role: { type: "string", description: "Subagent role label, e.g. 'Staff', 'Analyst'. Defaults to 'Staff'." },
|
|
4883
|
-
codename: { type: "string", description: "Optional subagent codename" },
|
|
4884
|
-
color_hex: { type: "string", description: "Optional subagent UI color, default '#64748b'" },
|
|
4911
|
+
chief_agent_id: { type: "string", description: "Chief agent ID (required for list_subagents)" },
|
|
4885
4912
|
template_id: { type: "string", description: "Template ID (required for apply_template)" },
|
|
4886
4913
|
target_kind: { type: "string", enum: ["conversation", "task", "scheduler_event"], description: "Run target kind (for propose_attach/commit_attach)" },
|
|
4887
4914
|
target_id: { type: "string", description: "Run target id (for propose_attach/commit_attach)" },
|
|
@@ -4938,13 +4965,11 @@ function registerSOPOps(
|
|
|
4938
4965
|
case "get": return handleSOPGet(supabase, userId, params);
|
|
4939
4966
|
case "update": return handleSOPUpdate(supabase, userId, params);
|
|
4940
4967
|
case "delete": return handleSOPDelete(supabase, userId, params);
|
|
4941
|
-
case "list_subagents": return
|
|
4942
|
-
case "create_subagent": return handleSOPCreateSubagent(supabase, userId, params);
|
|
4943
|
-
case "delete_subagent": return handleSOPDeleteSubagent(supabase, userId, params);
|
|
4968
|
+
case "list_subagents": return handleListSubagents(supabase, userId, params);
|
|
4944
4969
|
case "apply_template": return handleSOPApplyTemplate(supabase, userId, resolveAgent, params);
|
|
4945
4970
|
case "propose_attach": return handleProposeAttach({ supabase, userId, docKind: "sop", params });
|
|
4946
4971
|
case "commit_attach": return handleCommitAttach({ supabase, userId, docKind: "sop", params });
|
|
4947
|
-
default: return err(`Unknown action "${action}". Valid: list_templates, create, list, get, update, delete, list_subagents,
|
|
4972
|
+
default: return err(`Unknown action "${action}". Valid: list_templates, create, list, get, update, delete, list_subagents, apply_template, propose_attach, commit_attach`);
|
|
4948
4973
|
}
|
|
4949
4974
|
},
|
|
4950
4975
|
});
|
|
@@ -5185,7 +5210,12 @@ async function handleSOPDelete(supabase: SupabaseClient, userId: string, params:
|
|
|
5185
5210
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
5186
5211
|
}
|
|
5187
5212
|
|
|
5188
|
-
|
|
5213
|
+
// ── Shared subagent handlers (used by OFIERE_AGENT_OPS; SOP_OPS keeps a
|
|
5214
|
+
// convenience wrapper for `list_subagents` only). ──────────────────────────
|
|
5215
|
+
|
|
5216
|
+
const MAX_SUBAGENTS_PER_CHIEF = 5;
|
|
5217
|
+
|
|
5218
|
+
async function handleListSubagents(supabase: SupabaseClient, userId: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
5189
5219
|
try {
|
|
5190
5220
|
if (!params.chief_agent_id) return err("Missing required field: chief_agent_id");
|
|
5191
5221
|
const { data, error } = await supabase
|
|
@@ -5195,13 +5225,11 @@ async function handleSOPListSubagents(supabase: SupabaseClient, userId: string,
|
|
|
5195
5225
|
.eq("chief_agent_id", params.chief_agent_id as string)
|
|
5196
5226
|
.order("created_at", { ascending: true });
|
|
5197
5227
|
if (error) return err(error.message);
|
|
5198
|
-
return ok({ subagents: data || [], count: (data || []).length, max_allowed:
|
|
5228
|
+
return ok({ subagents: data || [], count: (data || []).length, max_allowed: MAX_SUBAGENTS_PER_CHIEF });
|
|
5199
5229
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
5200
5230
|
}
|
|
5201
5231
|
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
async function handleSOPCreateSubagent(supabase: SupabaseClient, userId: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
5232
|
+
async function handleCreateSubagent(supabase: SupabaseClient, userId: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
5205
5233
|
try {
|
|
5206
5234
|
const chiefAgentId = params.chief_agent_id as string | undefined;
|
|
5207
5235
|
const name = params.name as string | undefined;
|
|
@@ -5233,7 +5261,7 @@ async function handleSOPCreateSubagent(supabase: SupabaseClient, userId: string,
|
|
|
5233
5261
|
} catch (e) { return err(e instanceof Error ? e.message : String(e)); }
|
|
5234
5262
|
}
|
|
5235
5263
|
|
|
5236
|
-
async function
|
|
5264
|
+
async function handleDeleteSubagent(supabase: SupabaseClient, userId: string, params: Record<string, unknown>): Promise<ToolResult> {
|
|
5237
5265
|
try {
|
|
5238
5266
|
const subagentId = params.subagent_id as string | undefined;
|
|
5239
5267
|
if (!subagentId) return err("Missing required field: subagent_id");
|