Skip to content

Commit 236dcef

Browse files
author
guanbear
committed
fix(runtime): preserve Slack anchors from prompt arrays
1 parent 06cc674 commit 236dcef

2 files changed

Lines changed: 49 additions & 5 deletions

File tree

extensions/octoclaw-runtime/src/__tests__/extension-entry-resolvers.test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import fsSync from "node:fs";
22
import os from "node:os";
33
import path from "node:path";
44
import { afterEach, beforeEach, describe, expect, it } from "vitest";
5-
import { buildPromptContextProjection, extractInboundMessageTimestamp, parseOctoClawStatusFastPathCommand, parseOctoClawTaskActionFastPathCommand, resolveDelegationCapability, resolveReactionAckConfig } from "../extension-entry.js";
5+
import { buildPromptContextProjection, extractInboundMessageTimestamp, extractInboundMessageTimestampWithSource, parseOctoClawStatusFastPathCommand, parseOctoClawTaskActionFastPathCommand, resolveDelegationCapability, resolveReactionAckConfig } from "../extension-entry.js";
66
import { extractPromptText } from "../extension-entry-helpers.js";
77
import { nativeSpawnIntentStore } from "../delegate/native-spawn-intent-store.js";
88
import { policyState } from "../state/policy-state.js";
@@ -214,4 +214,32 @@ describe("extractInboundMessageTimestamp", () => {
214214
"",
215215
)).toBe("1777737951.706329");
216216
});
217+
218+
it("finds Slack timestamps inside OpenClaw before-prompt message arrays", () => {
219+
const event = {
220+
messages: [{
221+
role: "user",
222+
content: [{
223+
type: "text",
224+
text: [
225+
"Conversation info (untrusted metadata):",
226+
"```json",
227+
"{",
228+
" \"message_id\": \"1780479647.749959\",",
229+
" \"reply_to_id\": \"1780479647.749959\"",
230+
"}",
231+
"```",
232+
"",
233+
"委派子agent 帮我审计 Macmini 上 OpenClaw/OctoClaw 的后台任务。",
234+
].join("\n"),
235+
}],
236+
}],
237+
};
238+
239+
expect(extractInboundMessageTimestamp({}, event, "")).toBe("1780479647.749959");
240+
expect(extractInboundMessageTimestampWithSource({}, event, "")).toEqual({
241+
ts: "1780479647.749959",
242+
source: "event",
243+
});
244+
});
217245
});

extensions/octoclaw-runtime/src/inbound-timestamps.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,20 @@ const INBOUND_MESSAGE_TS_KEYS = new Set([
1717
]);
1818

1919
export function findInboundMessageTimestamp(value: unknown, depth = 0, seen = new Set<object>()): string {
20-
if (depth > 5 || value === null || value === undefined) return "";
20+
if (value === null || value === undefined) return "";
2121
if (typeof value === "string") {
2222
const text = value.trim();
2323
return SLACK_MESSAGE_TS_PATTERN.test(text) ? text : "";
2424
}
25-
if (typeof value !== "object" || Array.isArray(value)) return "";
25+
if (depth > 5) return "";
26+
if (Array.isArray(value)) {
27+
for (const item of value) {
28+
const nested = findInboundMessageTimestamp(item, depth + 1, seen);
29+
if (nested) return nested;
30+
}
31+
return "";
32+
}
33+
if (typeof value !== "object") return "";
2634
if (seen.has(value)) return "";
2735
seen.add(value);
2836
const record = value as UnknownRecord;
@@ -132,7 +140,7 @@ export function resolveSlackMessageReceivedSessionKey(event: UnknownRecord, ctx:
132140
/** Scan ALL string values in an object tree for a Slack ts pattern.
133141
* Used as a fallback when the key name is non-standard. */
134142
function findAnySlackTs(value: unknown, depth = 0, seen = new Set<object>()): string {
135-
if (depth > 4 || value === null || value === undefined) return "";
143+
if (value === null || value === undefined) return "";
136144
if (typeof value === "string") {
137145
// Only match strings that look like a standalone Slack ts (not embedded in a larger number)
138146
if (SLACK_MESSAGE_TS_PATTERN.test(value.trim())) return value.trim();
@@ -141,7 +149,15 @@ function findAnySlackTs(value: unknown, depth = 0, seen = new Set<object>()): st
141149
if (m) return m[1];
142150
return "";
143151
}
144-
if (typeof value !== "object" || Array.isArray(value)) return "";
152+
if (depth > 4) return "";
153+
if (Array.isArray(value)) {
154+
for (const item of value) {
155+
const found = findAnySlackTs(item, depth + 1, seen);
156+
if (found) return found;
157+
}
158+
return "";
159+
}
160+
if (typeof value !== "object") return "";
145161
if (seen.has(value as object)) return "";
146162
seen.add(value as object);
147163
for (const v of Object.values(value as Record<string, unknown>)) {

0 commit comments

Comments
 (0)