ofiere-openclaw-plugin 4.38.0 → 4.39.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/attachments.ts +75 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofiere-openclaw-plugin",
3
- "version": "4.38.0",
3
+ "version": "4.39.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"],
@@ -277,27 +277,16 @@ function isSystemName(name: string): boolean {
277
277
  return s === "" || s === "ofiere" || s === "openclaw" || s === "system" || s === "plugin" || s === "gateway" || s.includes("plugin");
278
278
  }
279
279
 
280
- async function buildAttachmentBlock(args: {
280
+ // Render a block from explicit doc-id lists. Used by both the dispatch-params
281
+ // path (when workflow/task-dispatcher hands ids in via ctx) and the conversation
282
+ // fallback path (when no explicit ids are present).
283
+ async function renderBlockForIds(args: {
281
284
  supabase: SupabaseClient;
282
285
  userId: string;
283
- agentId: string;
286
+ sopIds: string[];
287
+ fwIds: string[];
284
288
  }): Promise<string> {
285
- const { supabase, userId, agentId } = args;
286
-
287
- // Find the most recently active conversation for this agent. The dashboard
288
- // bumps `updated_at` whenever a message is sent or attachments change, so
289
- // this gives us the right run target most of the time.
290
- const { data: convRow } = await supabase
291
- .from("conversations")
292
- .select("id, attached_sop_ids, attached_framework_ids")
293
- .eq("user_id", userId)
294
- .eq("agent_id", agentId)
295
- .order("updated_at", { ascending: false })
296
- .limit(1)
297
- .maybeSingle();
298
-
299
- const sopIds: string[] = (convRow?.attached_sop_ids as string[] | null) || [];
300
- const fwIds: string[] = (convRow?.attached_framework_ids as string[] | null) || [];
289
+ const { supabase, userId, sopIds, fwIds } = args;
301
290
  if (!sopIds.length && !fwIds.length) return "";
302
291
 
303
292
  const [sopsRes, fwsRes] = await Promise.all([
@@ -329,6 +318,57 @@ async function buildAttachmentBlock(args: {
329
318
  return renderAttachmentBlock({ sops, frameworks });
330
319
  }
331
320
 
321
+ // Pluck attachment ids from the `before_prompt_build` ctx. Exact path varies by
322
+ // the dispatch surface that fires the prompt build, so we probe several known
323
+ // locations. Workflow executor + task-dispatcher edge function both stash ids
324
+ // under `metadata` on their request frames.
325
+ function readDispatchAttachmentIds(ctx: any): { sopIds: string[]; fwIds: string[] } {
326
+ const candidates: Array<Record<string, unknown> | undefined> = [
327
+ ctx?.metadata,
328
+ ctx?.params?.metadata,
329
+ ctx?.payload?.metadata,
330
+ ctx?.request?.metadata,
331
+ ctx?.options?.metadata,
332
+ ctx, // last resort: top level
333
+ ];
334
+ for (const c of candidates) {
335
+ if (!c || typeof c !== "object") continue;
336
+ const sop = (c as any).attached_sop_ids;
337
+ const fw = (c as any).attached_framework_ids;
338
+ if (Array.isArray(sop) || Array.isArray(fw)) {
339
+ return {
340
+ sopIds: Array.isArray(sop) ? sop.filter((x: unknown): x is string => typeof x === "string") : [],
341
+ fwIds: Array.isArray(fw) ? fw.filter((x: unknown): x is string => typeof x === "string") : [],
342
+ };
343
+ }
344
+ }
345
+ return { sopIds: [], fwIds: [] };
346
+ }
347
+
348
+ async function buildAttachmentBlock(args: {
349
+ supabase: SupabaseClient;
350
+ userId: string;
351
+ agentId: string;
352
+ }): Promise<string> {
353
+ const { supabase, userId, agentId } = args;
354
+
355
+ // Find the most recently active conversation for this agent. The dashboard
356
+ // bumps `updated_at` whenever a message is sent or attachments change, so
357
+ // this gives us the right run target most of the time.
358
+ const { data: convRow } = await supabase
359
+ .from("conversations")
360
+ .select("id, attached_sop_ids, attached_framework_ids")
361
+ .eq("user_id", userId)
362
+ .eq("agent_id", agentId)
363
+ .order("updated_at", { ascending: false })
364
+ .limit(1)
365
+ .maybeSingle();
366
+
367
+ const sopIds: string[] = (convRow?.attached_sop_ids as string[] | null) || [];
368
+ const fwIds: string[] = (convRow?.attached_framework_ids as string[] | null) || [];
369
+ return renderBlockForIds({ supabase, userId, sopIds, fwIds });
370
+ }
371
+
332
372
  export function registerAttachmentContextHook(args: {
333
373
  api: any;
334
374
  supabase: SupabaseClient;
@@ -351,6 +391,23 @@ export function registerAttachmentContextHook(args: {
351
391
  }
352
392
  if (!resolvedAgentId) return;
353
393
 
394
+ // Dispatch-params path: workflow executor + task-dispatcher edge function
395
+ // can stash explicit `attached_sop_ids` / `attached_framework_ids` on the
396
+ // chat.send frame's metadata. When present, prefer them over the
397
+ // most-recent-conversation lookup and bypass cache (per-dispatch ids).
398
+ const dispatchIds = readDispatchAttachmentIds(ctx);
399
+ if (dispatchIds.sopIds.length || dispatchIds.fwIds.length) {
400
+ api.logger?.debug?.(
401
+ `[ofiere-attach] dispatch ids agent=${resolvedAgentId} sops=${dispatchIds.sopIds.length} fws=${dispatchIds.fwIds.length}`,
402
+ );
403
+ const block = await renderBlockForIds({
404
+ supabase, userId,
405
+ sopIds: dispatchIds.sopIds,
406
+ fwIds: dispatchIds.fwIds,
407
+ });
408
+ return block ? { appendSystemContext: block } : undefined;
409
+ }
410
+
354
411
  const cacheKey = resolvedAgentId;
355
412
  const cached = attachmentCache.get(cacheKey);
356
413
  if (cached) {