ofiere-openclaw-plugin 4.50.0-probe.2 → 4.50.1
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/dist/src/tools.js +46 -112
- package/package.json +1 -1
- package/src/tools.ts +43 -116
package/dist/src/tools.js
CHANGED
|
@@ -21,6 +21,35 @@ function ok(data) {
|
|
|
21
21
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
+
// Extract plain text from a message that may be a plain string, a `{text}`
|
|
25
|
+
// envelope, or — under OpenClaw 2026.5+ — a structured content array such as
|
|
26
|
+
// `[{type:'text', text:'...'}, {type:'thinking', thinking:'...'}]`.
|
|
27
|
+
//
|
|
28
|
+
// BUG 12 fix (cycle 7b BUGSHOOT-5 → cycle 10 pivot): the prior inline
|
|
29
|
+
// expression returned the array value itself instead of joining the text
|
|
30
|
+
// parts because `||` short-circuited on the truthy array. Result: every
|
|
31
|
+
// staff dispatch persisted empty content. Centralising the logic in one
|
|
32
|
+
// helper avoids the same bug recurring at every call site.
|
|
33
|
+
function extractMessageText(msg) {
|
|
34
|
+
if (typeof msg === "string")
|
|
35
|
+
return msg;
|
|
36
|
+
if (typeof msg?.text === "string")
|
|
37
|
+
return msg.text;
|
|
38
|
+
if (typeof msg?.content === "string")
|
|
39
|
+
return msg.content;
|
|
40
|
+
if (typeof msg?.message?.content === "string")
|
|
41
|
+
return msg.message.content;
|
|
42
|
+
const arr = Array.isArray(msg?.content) ? msg.content
|
|
43
|
+
: Array.isArray(msg?.message?.content) ? msg.message.content
|
|
44
|
+
: null;
|
|
45
|
+
if (arr) {
|
|
46
|
+
return arr
|
|
47
|
+
.filter((c) => c?.type === "text" && typeof c?.text === "string")
|
|
48
|
+
.map((c) => c.text)
|
|
49
|
+
.join("\n");
|
|
50
|
+
}
|
|
51
|
+
return "";
|
|
52
|
+
}
|
|
24
53
|
function err(message) {
|
|
25
54
|
return {
|
|
26
55
|
content: [{ type: "text", text: `Error: ${message}` }],
|
|
@@ -6385,12 +6414,6 @@ supabase, config) {
|
|
|
6385
6414
|
registerAttachmentContextHook({ api, supabase, userId, fallbackAgentId, resolveAgent });
|
|
6386
6415
|
// ── Register agent_end hook for server-side brain extraction ──
|
|
6387
6416
|
registerBrainExtractionHook(api, supabase, userId, fallbackAgentId);
|
|
6388
|
-
// ── CYCLE 10 PROBE — verify subagent_* hook payload shapes ─────────────
|
|
6389
|
-
// Probe-only build (4.50.0-probe.x). Logs full payload on first fire of
|
|
6390
|
-
// each native subagent hook + triggers a one-shot subagent.run 8s after
|
|
6391
|
-
// init so we capture spawning → spawned → ended lifecycle. Removed in
|
|
6392
|
-
// 4.50.0 production release.
|
|
6393
|
-
registerCycle10Probe(api);
|
|
6394
6417
|
// ── Count and log ──
|
|
6395
6418
|
const toolCount = 16;
|
|
6396
6419
|
const callerName = getCallingAgentName(api);
|
|
@@ -6425,22 +6448,21 @@ function registerBrainExtractionHook(api, supabase, userId, fallbackAgentId) {
|
|
|
6425
6448
|
return;
|
|
6426
6449
|
}
|
|
6427
6450
|
// Find last user + last assistant message
|
|
6451
|
+
// BUG 12 fix: extractMessageText handles structured content arrays
|
|
6452
|
+
// (OpenClaw 2026.5+ delivers `[{type:'text',text:'X'},{type:'thinking',...}]`,
|
|
6453
|
+
// not plain strings). Prior inline expression returned the array, which
|
|
6454
|
+
// typeof-checked to "object" → both lastUser/lastAssistant became "".
|
|
6428
6455
|
let lastUser = "";
|
|
6429
6456
|
let lastAssistant = "";
|
|
6430
6457
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
6431
6458
|
const msg = messages[i];
|
|
6432
6459
|
const role = msg?.role || msg?.message?.role;
|
|
6433
|
-
const text =
|
|
6434
|
-
: msg?.text || msg?.content || msg?.message?.content
|
|
6435
|
-
?.filter?.((c) => c.type === "text")
|
|
6436
|
-
?.map?.((c) => c.text)
|
|
6437
|
-
?.join?.("\n")
|
|
6438
|
-
|| (typeof msg?.message?.content === "string" ? msg.message.content : "");
|
|
6460
|
+
const text = extractMessageText(msg);
|
|
6439
6461
|
if (!lastAssistant && (role === "assistant" || role === "model")) {
|
|
6440
|
-
lastAssistant =
|
|
6462
|
+
lastAssistant = text;
|
|
6441
6463
|
}
|
|
6442
6464
|
if (!lastUser && role === "user") {
|
|
6443
|
-
lastUser =
|
|
6465
|
+
lastUser = text;
|
|
6444
6466
|
}
|
|
6445
6467
|
if (lastUser && lastAssistant)
|
|
6446
6468
|
break;
|
|
@@ -6523,15 +6545,23 @@ function registerBrainExtractionHook(api, supabase, userId, fallbackAgentId) {
|
|
|
6523
6545
|
const reportBody = taskId
|
|
6524
6546
|
? `Staff ${staff.name}${staff.role ? ` (${staff.role})` : ""} reported on task ${taskId}:\n\n${excerpt}`
|
|
6525
6547
|
: `Staff ${staff.name}${staff.role ? ` (${staff.role})` : ""} reported:\n\n${excerpt}`;
|
|
6526
|
-
|
|
6548
|
+
// BUG 13 fix (cycle 10 pivot): tier was 'L4_episodic' which is
|
|
6549
|
+
// NOT in the agent_memories.tier CHECK enum (L1_focus, L2_episode,
|
|
6550
|
+
// L3_pattern, L4_rule, L5_persona) → insert silently failed.
|
|
6551
|
+
// Use L2_episode (the actual "episodic memory" tier). source
|
|
6552
|
+
// 'staff_report' added to enum via migration in same cycle.
|
|
6553
|
+
const { error: memErr } = await supabase.from("agent_memories").insert({
|
|
6527
6554
|
user_id: userId,
|
|
6528
6555
|
agent_id: staff.chief_agent_id,
|
|
6529
|
-
tier: "
|
|
6556
|
+
tier: "L2_episode",
|
|
6530
6557
|
content: reportBody,
|
|
6531
6558
|
source: "staff_report",
|
|
6532
6559
|
importance: 5,
|
|
6533
6560
|
context_key: taskId ? `staff_report:${staffDispatchSubagentId}:${taskId}` : `staff_report:${staffDispatchSubagentId}`,
|
|
6534
6561
|
});
|
|
6562
|
+
if (memErr) {
|
|
6563
|
+
api.logger.warn?.(`[ofiere-staff-report] memory insert failed: ${memErr.message}`);
|
|
6564
|
+
}
|
|
6535
6565
|
api.logger.info?.(`[ofiere-staff-report] memory written for chief ${staff.chief_agent_id} from staff ${staff.name}`);
|
|
6536
6566
|
// BUG 9 fix (BUGSHOOT-2): mark task_dispatch_log row complete
|
|
6537
6567
|
// with the assistant's response preview. Without this the log
|
|
@@ -6753,102 +6783,6 @@ function registerBrainExtractionHook(api, supabase, userId, fallbackAgentId) {
|
|
|
6753
6783
|
api.logger.debug?.("[ofiere] Could not register agent_end hook — may not be supported in this OpenClaw version");
|
|
6754
6784
|
}
|
|
6755
6785
|
}
|
|
6756
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6757
|
-
// CYCLE 10 PROBE — REMOVE/DISABLE BEFORE PRODUCTION 4.50.x
|
|
6758
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6759
|
-
// One-shot diagnostic that logs the full payload shape of every native
|
|
6760
|
-
// subagent_* hook, then triggers a single api.runtime.subagent.run so the
|
|
6761
|
-
// lifecycle fires end-to-end. Used to verify field names before the real
|
|
6762
|
-
// subagent_ended handler is written. Activated by env var
|
|
6763
|
-
// OFIERE_CYCLE10_PROBE=1; otherwise inert.
|
|
6764
|
-
//
|
|
6765
|
-
// Captured in cycle 10 BUGSHOOT under hook key [ofiere-probe].
|
|
6766
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6767
|
-
function registerCycle10Probe(api) {
|
|
6768
|
-
const safeStringify = (obj, max = 4000) => {
|
|
6769
|
-
try {
|
|
6770
|
-
const seen = new WeakSet();
|
|
6771
|
-
const out = JSON.stringify(obj, (_k, v) => {
|
|
6772
|
-
if (typeof v === "object" && v !== null) {
|
|
6773
|
-
if (seen.has(v))
|
|
6774
|
-
return "[Circular]";
|
|
6775
|
-
seen.add(v);
|
|
6776
|
-
}
|
|
6777
|
-
if (typeof v === "function")
|
|
6778
|
-
return `[Function ${v.name || "anon"}]`;
|
|
6779
|
-
return v;
|
|
6780
|
-
}, 2);
|
|
6781
|
-
return out.length > max ? out.slice(0, max) + "...[truncated]" : out;
|
|
6782
|
-
}
|
|
6783
|
-
catch (e) {
|
|
6784
|
-
return `[stringify-fail: ${e instanceof Error ? e.message : String(e)}]`;
|
|
6785
|
-
}
|
|
6786
|
-
};
|
|
6787
|
-
const hookNames = [
|
|
6788
|
-
"subagent_spawning",
|
|
6789
|
-
"subagent_spawned",
|
|
6790
|
-
"subagent_delivery_target",
|
|
6791
|
-
"subagent_ended",
|
|
6792
|
-
];
|
|
6793
|
-
for (const hook of hookNames) {
|
|
6794
|
-
try {
|
|
6795
|
-
api.on?.(hook, (event, ctx) => {
|
|
6796
|
-
try {
|
|
6797
|
-
api.logger.info?.(`[ofiere-probe] ${hook} event=${safeStringify(event, 2000)} ctx=${safeStringify(ctx, 2000)}`);
|
|
6798
|
-
}
|
|
6799
|
-
catch (e) {
|
|
6800
|
-
api.logger.warn?.(`[ofiere-probe] ${hook} log failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6801
|
-
}
|
|
6802
|
-
});
|
|
6803
|
-
api.logger.info?.(`[ofiere-probe] ${hook} hook registered`);
|
|
6804
|
-
}
|
|
6805
|
-
catch (e) {
|
|
6806
|
-
api.logger.warn?.(`[ofiere-probe] ${hook} hook register failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6807
|
-
}
|
|
6808
|
-
}
|
|
6809
|
-
// One-shot spawn 8s after init so the gateway is fully up.
|
|
6810
|
-
setTimeout(async () => {
|
|
6811
|
-
const sessionKey = `agent:celia:subagent:probe-${Date.now().toString(36).slice(-6)}`;
|
|
6812
|
-
api.logger.info?.(`[ofiere-probe] firing api.runtime.subagent.run sessionKey=${sessionKey}`);
|
|
6813
|
-
try {
|
|
6814
|
-
const runtime = api?.runtime;
|
|
6815
|
-
if (!runtime?.subagent?.run) {
|
|
6816
|
-
api.logger.error?.(`[ofiere-probe] api.runtime.subagent.run NOT AVAILABLE on this OpenClaw version. ` +
|
|
6817
|
-
`runtime keys: ${runtime ? Object.keys(runtime).join(",") : "(no runtime)"}`);
|
|
6818
|
-
return;
|
|
6819
|
-
}
|
|
6820
|
-
const result = await runtime.subagent.run({
|
|
6821
|
-
sessionKey,
|
|
6822
|
-
message: "Reply with exactly the text PROBE-OK and nothing else.",
|
|
6823
|
-
deliver: false,
|
|
6824
|
-
});
|
|
6825
|
-
api.logger.info?.(`[ofiere-probe] subagent.run returned ${safeStringify(result, 1000)}`);
|
|
6826
|
-
// Try waitForRun + getSessionMessages immediately so we capture the
|
|
6827
|
-
// full transcript shape even before subagent_ended fires.
|
|
6828
|
-
if (result?.runId && runtime.subagent.waitForRun) {
|
|
6829
|
-
try {
|
|
6830
|
-
const waitResult = await runtime.subagent.waitForRun({ runId: result.runId, timeoutMs: 30000 });
|
|
6831
|
-
api.logger.info?.(`[ofiere-probe] waitForRun returned ${safeStringify(waitResult, 2000)}`);
|
|
6832
|
-
}
|
|
6833
|
-
catch (e) {
|
|
6834
|
-
api.logger.warn?.(`[ofiere-probe] waitForRun threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
6835
|
-
}
|
|
6836
|
-
}
|
|
6837
|
-
if (runtime.subagent.getSessionMessages) {
|
|
6838
|
-
try {
|
|
6839
|
-
const msgsResult = await runtime.subagent.getSessionMessages({ sessionKey, limit: 10 });
|
|
6840
|
-
api.logger.info?.(`[ofiere-probe] getSessionMessages returned ${safeStringify(msgsResult, 4000)}`);
|
|
6841
|
-
}
|
|
6842
|
-
catch (e) {
|
|
6843
|
-
api.logger.warn?.(`[ofiere-probe] getSessionMessages threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
6844
|
-
}
|
|
6845
|
-
}
|
|
6846
|
-
}
|
|
6847
|
-
catch (e) {
|
|
6848
|
-
api.logger.error?.(`[ofiere-probe] subagent.run threw: ${e instanceof Error ? `${e.name}: ${e.message}\n${e.stack}` : String(e)}`);
|
|
6849
|
-
}
|
|
6850
|
-
}, 8000);
|
|
6851
|
-
}
|
|
6852
6786
|
// ── Brain Context Bootstrap Injection ──────────────────────────────────────
|
|
6853
6787
|
// Injects the calling agent's active memories into the system prompt via
|
|
6854
6788
|
// api.on("before_prompt_build"). Uses the TMT hierarchy:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofiere-openclaw-plugin",
|
|
3
|
-
"version": "4.50.
|
|
3
|
+
"version": "4.50.1",
|
|
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
|
@@ -36,6 +36,32 @@ function ok(data: unknown): ToolResult {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// Extract plain text from a message that may be a plain string, a `{text}`
|
|
40
|
+
// envelope, or — under OpenClaw 2026.5+ — a structured content array such as
|
|
41
|
+
// `[{type:'text', text:'...'}, {type:'thinking', thinking:'...'}]`.
|
|
42
|
+
//
|
|
43
|
+
// BUG 12 fix (cycle 7b BUGSHOOT-5 → cycle 10 pivot): the prior inline
|
|
44
|
+
// expression returned the array value itself instead of joining the text
|
|
45
|
+
// parts because `||` short-circuited on the truthy array. Result: every
|
|
46
|
+
// staff dispatch persisted empty content. Centralising the logic in one
|
|
47
|
+
// helper avoids the same bug recurring at every call site.
|
|
48
|
+
function extractMessageText(msg: any): string {
|
|
49
|
+
if (typeof msg === "string") return msg;
|
|
50
|
+
if (typeof msg?.text === "string") return msg.text;
|
|
51
|
+
if (typeof msg?.content === "string") return msg.content;
|
|
52
|
+
if (typeof msg?.message?.content === "string") return msg.message.content;
|
|
53
|
+
const arr = Array.isArray(msg?.content) ? msg.content
|
|
54
|
+
: Array.isArray(msg?.message?.content) ? msg.message.content
|
|
55
|
+
: null;
|
|
56
|
+
if (arr) {
|
|
57
|
+
return arr
|
|
58
|
+
.filter((c: any) => c?.type === "text" && typeof c?.text === "string")
|
|
59
|
+
.map((c: any) => c.text)
|
|
60
|
+
.join("\n");
|
|
61
|
+
}
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
|
|
39
65
|
function err(message: string): ToolResult {
|
|
40
66
|
return {
|
|
41
67
|
content: [{ type: "text" as const, text: `Error: ${message}` }],
|
|
@@ -6536,13 +6562,6 @@ export function registerTools(
|
|
|
6536
6562
|
// ── Register agent_end hook for server-side brain extraction ──
|
|
6537
6563
|
registerBrainExtractionHook(api, supabase, userId, fallbackAgentId);
|
|
6538
6564
|
|
|
6539
|
-
// ── CYCLE 10 PROBE — verify subagent_* hook payload shapes ─────────────
|
|
6540
|
-
// Probe-only build (4.50.0-probe.x). Logs full payload on first fire of
|
|
6541
|
-
// each native subagent hook + triggers a one-shot subagent.run 8s after
|
|
6542
|
-
// init so we capture spawning → spawned → ended lifecycle. Removed in
|
|
6543
|
-
// 4.50.0 production release.
|
|
6544
|
-
registerCycle10Probe(api);
|
|
6545
|
-
|
|
6546
6565
|
// ── Count and log ──
|
|
6547
6566
|
const toolCount = 16;
|
|
6548
6567
|
const callerName = getCallingAgentName(api);
|
|
@@ -6586,23 +6605,22 @@ function registerBrainExtractionHook(
|
|
|
6586
6605
|
}
|
|
6587
6606
|
|
|
6588
6607
|
// Find last user + last assistant message
|
|
6608
|
+
// BUG 12 fix: extractMessageText handles structured content arrays
|
|
6609
|
+
// (OpenClaw 2026.5+ delivers `[{type:'text',text:'X'},{type:'thinking',...}]`,
|
|
6610
|
+
// not plain strings). Prior inline expression returned the array, which
|
|
6611
|
+
// typeof-checked to "object" → both lastUser/lastAssistant became "".
|
|
6589
6612
|
let lastUser = "";
|
|
6590
6613
|
let lastAssistant = "";
|
|
6591
6614
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
6592
6615
|
const msg = messages[i];
|
|
6593
6616
|
const role = msg?.role || msg?.message?.role;
|
|
6594
|
-
const text =
|
|
6595
|
-
: msg?.text || msg?.content || msg?.message?.content
|
|
6596
|
-
?.filter?.((c: any) => c.type === "text")
|
|
6597
|
-
?.map?.((c: any) => c.text)
|
|
6598
|
-
?.join?.("\n")
|
|
6599
|
-
|| (typeof msg?.message?.content === "string" ? msg.message.content : "");
|
|
6617
|
+
const text = extractMessageText(msg);
|
|
6600
6618
|
|
|
6601
6619
|
if (!lastAssistant && (role === "assistant" || role === "model")) {
|
|
6602
|
-
lastAssistant =
|
|
6620
|
+
lastAssistant = text;
|
|
6603
6621
|
}
|
|
6604
6622
|
if (!lastUser && role === "user") {
|
|
6605
|
-
lastUser =
|
|
6623
|
+
lastUser = text;
|
|
6606
6624
|
}
|
|
6607
6625
|
if (lastUser && lastAssistant) break;
|
|
6608
6626
|
}
|
|
@@ -6689,15 +6707,23 @@ function registerBrainExtractionHook(
|
|
|
6689
6707
|
const reportBody = taskId
|
|
6690
6708
|
? `Staff ${staff.name}${staff.role ? ` (${staff.role})` : ""} reported on task ${taskId}:\n\n${excerpt}`
|
|
6691
6709
|
: `Staff ${staff.name}${staff.role ? ` (${staff.role})` : ""} reported:\n\n${excerpt}`;
|
|
6692
|
-
|
|
6710
|
+
// BUG 13 fix (cycle 10 pivot): tier was 'L4_episodic' which is
|
|
6711
|
+
// NOT in the agent_memories.tier CHECK enum (L1_focus, L2_episode,
|
|
6712
|
+
// L3_pattern, L4_rule, L5_persona) → insert silently failed.
|
|
6713
|
+
// Use L2_episode (the actual "episodic memory" tier). source
|
|
6714
|
+
// 'staff_report' added to enum via migration in same cycle.
|
|
6715
|
+
const { error: memErr } = await supabase.from("agent_memories").insert({
|
|
6693
6716
|
user_id: userId,
|
|
6694
6717
|
agent_id: staff.chief_agent_id,
|
|
6695
|
-
tier: "
|
|
6718
|
+
tier: "L2_episode",
|
|
6696
6719
|
content: reportBody,
|
|
6697
6720
|
source: "staff_report",
|
|
6698
6721
|
importance: 5,
|
|
6699
6722
|
context_key: taskId ? `staff_report:${staffDispatchSubagentId}:${taskId}` : `staff_report:${staffDispatchSubagentId}`,
|
|
6700
6723
|
});
|
|
6724
|
+
if (memErr) {
|
|
6725
|
+
api.logger.warn?.(`[ofiere-staff-report] memory insert failed: ${memErr.message}`);
|
|
6726
|
+
}
|
|
6701
6727
|
api.logger.info?.(`[ofiere-staff-report] memory written for chief ${staff.chief_agent_id} from staff ${staff.name}`);
|
|
6702
6728
|
|
|
6703
6729
|
// BUG 9 fix (BUGSHOOT-2): mark task_dispatch_log row complete
|
|
@@ -6932,105 +6958,6 @@ function registerBrainExtractionHook(
|
|
|
6932
6958
|
}
|
|
6933
6959
|
}
|
|
6934
6960
|
|
|
6935
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6936
|
-
// CYCLE 10 PROBE — REMOVE/DISABLE BEFORE PRODUCTION 4.50.x
|
|
6937
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6938
|
-
// One-shot diagnostic that logs the full payload shape of every native
|
|
6939
|
-
// subagent_* hook, then triggers a single api.runtime.subagent.run so the
|
|
6940
|
-
// lifecycle fires end-to-end. Used to verify field names before the real
|
|
6941
|
-
// subagent_ended handler is written. Activated by env var
|
|
6942
|
-
// OFIERE_CYCLE10_PROBE=1; otherwise inert.
|
|
6943
|
-
//
|
|
6944
|
-
// Captured in cycle 10 BUGSHOOT under hook key [ofiere-probe].
|
|
6945
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6946
|
-
|
|
6947
|
-
function registerCycle10Probe(api: any): void {
|
|
6948
|
-
const safeStringify = (obj: unknown, max = 4000): string => {
|
|
6949
|
-
try {
|
|
6950
|
-
const seen = new WeakSet<object>();
|
|
6951
|
-
const out = JSON.stringify(obj, (_k, v) => {
|
|
6952
|
-
if (typeof v === "object" && v !== null) {
|
|
6953
|
-
if (seen.has(v)) return "[Circular]";
|
|
6954
|
-
seen.add(v);
|
|
6955
|
-
}
|
|
6956
|
-
if (typeof v === "function") return `[Function ${v.name || "anon"}]`;
|
|
6957
|
-
return v;
|
|
6958
|
-
}, 2);
|
|
6959
|
-
return out.length > max ? out.slice(0, max) + "...[truncated]" : out;
|
|
6960
|
-
} catch (e) {
|
|
6961
|
-
return `[stringify-fail: ${e instanceof Error ? e.message : String(e)}]`;
|
|
6962
|
-
}
|
|
6963
|
-
};
|
|
6964
|
-
|
|
6965
|
-
const hookNames = [
|
|
6966
|
-
"subagent_spawning",
|
|
6967
|
-
"subagent_spawned",
|
|
6968
|
-
"subagent_delivery_target",
|
|
6969
|
-
"subagent_ended",
|
|
6970
|
-
];
|
|
6971
|
-
for (const hook of hookNames) {
|
|
6972
|
-
try {
|
|
6973
|
-
api.on?.(hook, (event: any, ctx: any) => {
|
|
6974
|
-
try {
|
|
6975
|
-
api.logger.info?.(
|
|
6976
|
-
`[ofiere-probe] ${hook} event=${safeStringify(event, 2000)} ctx=${safeStringify(ctx, 2000)}`,
|
|
6977
|
-
);
|
|
6978
|
-
} catch (e) {
|
|
6979
|
-
api.logger.warn?.(`[ofiere-probe] ${hook} log failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6980
|
-
}
|
|
6981
|
-
});
|
|
6982
|
-
api.logger.info?.(`[ofiere-probe] ${hook} hook registered`);
|
|
6983
|
-
} catch (e) {
|
|
6984
|
-
api.logger.warn?.(`[ofiere-probe] ${hook} hook register failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6985
|
-
}
|
|
6986
|
-
}
|
|
6987
|
-
|
|
6988
|
-
// One-shot spawn 8s after init so the gateway is fully up.
|
|
6989
|
-
setTimeout(async () => {
|
|
6990
|
-
const sessionKey = `agent:celia:subagent:probe-${Date.now().toString(36).slice(-6)}`;
|
|
6991
|
-
api.logger.info?.(`[ofiere-probe] firing api.runtime.subagent.run sessionKey=${sessionKey}`);
|
|
6992
|
-
try {
|
|
6993
|
-
const runtime = (api as any)?.runtime;
|
|
6994
|
-
if (!runtime?.subagent?.run) {
|
|
6995
|
-
api.logger.error?.(
|
|
6996
|
-
`[ofiere-probe] api.runtime.subagent.run NOT AVAILABLE on this OpenClaw version. ` +
|
|
6997
|
-
`runtime keys: ${runtime ? Object.keys(runtime).join(",") : "(no runtime)"}`,
|
|
6998
|
-
);
|
|
6999
|
-
return;
|
|
7000
|
-
}
|
|
7001
|
-
const result = await runtime.subagent.run({
|
|
7002
|
-
sessionKey,
|
|
7003
|
-
message: "Reply with exactly the text PROBE-OK and nothing else.",
|
|
7004
|
-
deliver: false,
|
|
7005
|
-
});
|
|
7006
|
-
api.logger.info?.(`[ofiere-probe] subagent.run returned ${safeStringify(result, 1000)}`);
|
|
7007
|
-
|
|
7008
|
-
// Try waitForRun + getSessionMessages immediately so we capture the
|
|
7009
|
-
// full transcript shape even before subagent_ended fires.
|
|
7010
|
-
if (result?.runId && runtime.subagent.waitForRun) {
|
|
7011
|
-
try {
|
|
7012
|
-
const waitResult = await runtime.subagent.waitForRun({ runId: result.runId, timeoutMs: 30000 });
|
|
7013
|
-
api.logger.info?.(`[ofiere-probe] waitForRun returned ${safeStringify(waitResult, 2000)}`);
|
|
7014
|
-
} catch (e) {
|
|
7015
|
-
api.logger.warn?.(`[ofiere-probe] waitForRun threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
7016
|
-
}
|
|
7017
|
-
}
|
|
7018
|
-
if (runtime.subagent.getSessionMessages) {
|
|
7019
|
-
try {
|
|
7020
|
-
const msgsResult = await runtime.subagent.getSessionMessages({ sessionKey, limit: 10 });
|
|
7021
|
-
api.logger.info?.(`[ofiere-probe] getSessionMessages returned ${safeStringify(msgsResult, 4000)}`);
|
|
7022
|
-
} catch (e) {
|
|
7023
|
-
api.logger.warn?.(`[ofiere-probe] getSessionMessages threw: ${e instanceof Error ? e.message : String(e)}`);
|
|
7024
|
-
}
|
|
7025
|
-
}
|
|
7026
|
-
} catch (e) {
|
|
7027
|
-
api.logger.error?.(
|
|
7028
|
-
`[ofiere-probe] subagent.run threw: ${e instanceof Error ? `${e.name}: ${e.message}\n${e.stack}` : String(e)}`,
|
|
7029
|
-
);
|
|
7030
|
-
}
|
|
7031
|
-
}, 8000);
|
|
7032
|
-
}
|
|
7033
|
-
|
|
7034
6961
|
// ── Brain Context Bootstrap Injection ──────────────────────────────────────
|
|
7035
6962
|
// Injects the calling agent's active memories into the system prompt via
|
|
7036
6963
|
// api.on("before_prompt_build"). Uses the TMT hierarchy:
|