ofiere-openclaw-plugin 4.48.0 → 4.50.0-probe.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/tools.ts +136 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofiere-openclaw-plugin",
3
- "version": "4.48.0",
3
+ "version": "4.50.0-probe.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/tools.ts CHANGED
@@ -6535,6 +6535,13 @@ export function registerTools(
6535
6535
  // ── Register agent_end hook for server-side brain extraction ──
6536
6536
  registerBrainExtractionHook(api, supabase, userId, fallbackAgentId);
6537
6537
 
6538
+ // ── CYCLE 10 PROBE — verify subagent_* hook payload shapes ─────────────
6539
+ // Probe-only build (4.50.0-probe.x). Logs full payload on first fire of
6540
+ // each native subagent hook + triggers a one-shot subagent.run 8s after
6541
+ // init so we capture spawning → spawned → ended lifecycle. Removed in
6542
+ // 4.50.0 production release.
6543
+ registerCycle10Probe(api);
6544
+
6538
6545
  // ── Count and log ──
6539
6546
  const toolCount = 16;
6540
6547
  const callerName = getCallingAgentName(api);
@@ -6562,10 +6569,20 @@ function registerBrainExtractionHook(
6562
6569
  ): void {
6563
6570
  try {
6564
6571
  api.on("agent_end", async (event: any, ctx: any) => {
6572
+ // Cycle 7b BUGSHOOT-4 — entry log is load-bearing: 4 prior cycles spent
6573
+ // chasing downstream symptoms because no log existed to prove the hook
6574
+ // even fired. If you're debugging staff-dispatch persistence and DO NOT
6575
+ // see this line in the gateway log, the hook never ran — investigate
6576
+ // hook registration / agent scoping before anything else.
6577
+ const _entrySessionKey = ctx?.sessionKey || event?.sessionKey || event?.context?.sessionKey || "(none)";
6578
+ api.logger.info?.(`[ofiere-brain] agent_end fired (sessionKey=${_entrySessionKey})`);
6565
6579
  try {
6566
6580
  // Extract messages from event — agent_end provides the conversation
6567
6581
  const messages: any[] = event?.messages || event?.context?.messages || [];
6568
- if (!messages || messages.length < 2) return;
6582
+ if (!messages || messages.length < 2) {
6583
+ api.logger.debug?.(`[ofiere-brain] agent_end early-exit: messages.length=${messages?.length ?? 0} (<2)`);
6584
+ return;
6585
+ }
6569
6586
 
6570
6587
  // Find last user + last assistant message
6571
6588
  let lastUser = "";
@@ -6589,8 +6606,15 @@ function registerBrainExtractionHook(
6589
6606
  if (lastUser && lastAssistant) break;
6590
6607
  }
6591
6608
 
6592
- // Skip trivial exchanges
6593
- if (lastUser.length < 20 || lastAssistant.length < 30) return;
6609
+ // Cycle 7b BUGSHOOT-4 — REMOVED early-return on short messages here.
6610
+ // The prior gate (`if lastUser<20 || lastAssistant<30 return`) sat
6611
+ // BEFORE the staff_report / task_dispatch_log / conversation_messages
6612
+ // writes, which silently killed every staff dispatch whose output was
6613
+ // shorter than 30 chars (e.g. smoke tests outputting "SMOKE-OK" = 8).
6614
+ // The trivial-skip is now applied just before the brain L1/L2/L3/L4
6615
+ // extraction below — those are noise filters, not bookkeeping.
6616
+ // Bookkeeping (dispatch_log completion, conversation messages,
6617
+ // staff_report) MUST run regardless of message length.
6594
6618
 
6595
6619
  // ── Agent identity resolution (FIX) ──────────────────────────
6596
6620
  // Priority: ctx.agentId (from PluginHookAgentContext, the CORRECT source)
@@ -6776,6 +6800,16 @@ function registerBrainExtractionHook(
6776
6800
  }
6777
6801
  }
6778
6802
 
6803
+ // Cycle 7b BUGSHOOT-4 — trivial-skip moved here from line ~6593.
6804
+ // Brain L1/L2/L3/L4 extraction skips trivial chit-chat to reduce
6805
+ // memory noise. This MUST sit AFTER staff_report + task_dispatch_log
6806
+ // bookkeeping above, otherwise short-output staff dispatches silently
6807
+ // fail to persist (root cause of cycles 7b BUGSHOOT 1-4).
6808
+ if (lastUser.length < 20 || lastAssistant.length < 30) {
6809
+ api.logger.debug?.(`[ofiere-brain] skip brain extraction (trivial: user=${lastUser.length}c assistant=${lastAssistant.length}c)`);
6810
+ return;
6811
+ }
6812
+
6779
6813
  // ── Fast Stream: Write L1_focus + L2_episode in parallel ──
6780
6814
  const rawContent = `User: ${lastUser}\nAssistant: ${lastAssistant}`;
6781
6815
  const immediateWrites: PromiseLike<any>[] = [];
@@ -6897,6 +6931,105 @@ function registerBrainExtractionHook(
6897
6931
  }
6898
6932
  }
6899
6933
 
6934
+ // ─────────────────────────────────────────────────────────────────────────────
6935
+ // CYCLE 10 PROBE — REMOVE/DISABLE BEFORE PRODUCTION 4.50.x
6936
+ // ─────────────────────────────────────────────────────────────────────────────
6937
+ // One-shot diagnostic that logs the full payload shape of every native
6938
+ // subagent_* hook, then triggers a single api.runtime.subagent.run so the
6939
+ // lifecycle fires end-to-end. Used to verify field names before the real
6940
+ // subagent_ended handler is written. Activated by env var
6941
+ // OFIERE_CYCLE10_PROBE=1; otherwise inert.
6942
+ //
6943
+ // Captured in cycle 10 BUGSHOOT under hook key [ofiere-probe].
6944
+ // ─────────────────────────────────────────────────────────────────────────────
6945
+
6946
+ function registerCycle10Probe(api: any): void {
6947
+ const safeStringify = (obj: unknown, max = 4000): string => {
6948
+ try {
6949
+ const seen = new WeakSet<object>();
6950
+ const out = JSON.stringify(obj, (_k, v) => {
6951
+ if (typeof v === "object" && v !== null) {
6952
+ if (seen.has(v)) return "[Circular]";
6953
+ seen.add(v);
6954
+ }
6955
+ if (typeof v === "function") return `[Function ${v.name || "anon"}]`;
6956
+ return v;
6957
+ }, 2);
6958
+ return out.length > max ? out.slice(0, max) + "...[truncated]" : out;
6959
+ } catch (e) {
6960
+ return `[stringify-fail: ${e instanceof Error ? e.message : String(e)}]`;
6961
+ }
6962
+ };
6963
+
6964
+ const hookNames = [
6965
+ "subagent_spawning",
6966
+ "subagent_spawned",
6967
+ "subagent_delivery_target",
6968
+ "subagent_ended",
6969
+ ];
6970
+ for (const hook of hookNames) {
6971
+ try {
6972
+ api.on?.(hook, (event: any, ctx: any) => {
6973
+ try {
6974
+ api.logger.info?.(
6975
+ `[ofiere-probe] ${hook} event=${safeStringify(event, 2000)} ctx=${safeStringify(ctx, 2000)}`,
6976
+ );
6977
+ } catch (e) {
6978
+ api.logger.warn?.(`[ofiere-probe] ${hook} log failed: ${e instanceof Error ? e.message : String(e)}`);
6979
+ }
6980
+ });
6981
+ api.logger.info?.(`[ofiere-probe] ${hook} hook registered`);
6982
+ } catch (e) {
6983
+ api.logger.warn?.(`[ofiere-probe] ${hook} hook register failed: ${e instanceof Error ? e.message : String(e)}`);
6984
+ }
6985
+ }
6986
+
6987
+ // One-shot spawn 8s after init so the gateway is fully up.
6988
+ setTimeout(async () => {
6989
+ const sessionKey = `agent:celia:subagent:probe-${Date.now().toString(36).slice(-6)}`;
6990
+ api.logger.info?.(`[ofiere-probe] firing api.runtime.subagent.run sessionKey=${sessionKey}`);
6991
+ try {
6992
+ const runtime = (api as any)?.runtime;
6993
+ if (!runtime?.subagent?.run) {
6994
+ api.logger.error?.(
6995
+ `[ofiere-probe] api.runtime.subagent.run NOT AVAILABLE on this OpenClaw version. ` +
6996
+ `runtime keys: ${runtime ? Object.keys(runtime).join(",") : "(no runtime)"}`,
6997
+ );
6998
+ return;
6999
+ }
7000
+ const result = await runtime.subagent.run({
7001
+ sessionKey,
7002
+ message: "Reply with exactly the text PROBE-OK and nothing else.",
7003
+ deliver: false,
7004
+ });
7005
+ api.logger.info?.(`[ofiere-probe] subagent.run returned ${safeStringify(result, 1000)}`);
7006
+
7007
+ // Try waitForRun + getSessionMessages immediately so we capture the
7008
+ // full transcript shape even before subagent_ended fires.
7009
+ if (result?.runId && runtime.subagent.waitForRun) {
7010
+ try {
7011
+ const waitResult = await runtime.subagent.waitForRun({ runId: result.runId, timeoutMs: 30000 });
7012
+ api.logger.info?.(`[ofiere-probe] waitForRun returned ${safeStringify(waitResult, 2000)}`);
7013
+ } catch (e) {
7014
+ api.logger.warn?.(`[ofiere-probe] waitForRun threw: ${e instanceof Error ? e.message : String(e)}`);
7015
+ }
7016
+ }
7017
+ if (runtime.subagent.getSessionMessages) {
7018
+ try {
7019
+ const msgsResult = await runtime.subagent.getSessionMessages({ sessionKey, limit: 10 });
7020
+ api.logger.info?.(`[ofiere-probe] getSessionMessages returned ${safeStringify(msgsResult, 4000)}`);
7021
+ } catch (e) {
7022
+ api.logger.warn?.(`[ofiere-probe] getSessionMessages threw: ${e instanceof Error ? e.message : String(e)}`);
7023
+ }
7024
+ }
7025
+ } catch (e) {
7026
+ api.logger.error?.(
7027
+ `[ofiere-probe] subagent.run threw: ${e instanceof Error ? `${e.name}: ${e.message}\n${e.stack}` : String(e)}`,
7028
+ );
7029
+ }
7030
+ }, 8000);
7031
+ }
7032
+
6900
7033
  // ── Brain Context Bootstrap Injection ──────────────────────────────────────
6901
7034
  // Injects the calling agent's active memories into the system prompt via
6902
7035
  // api.on("before_prompt_build"). Uses the TMT hierarchy: