mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
refactor(agents): share text block extraction helper
This commit is contained in:
19
src/agents/content-blocks.test.ts
Normal file
19
src/agents/content-blocks.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { collectTextContentBlocks } from "./content-blocks.js";
|
||||
|
||||
describe("collectTextContentBlocks", () => {
|
||||
it("collects text content blocks in order", () => {
|
||||
const blocks = [
|
||||
{ type: "text", text: "first" },
|
||||
{ type: "image", data: "abc" },
|
||||
{ type: "text", text: "second" },
|
||||
];
|
||||
|
||||
expect(collectTextContentBlocks(blocks)).toEqual(["first", "second"]);
|
||||
});
|
||||
|
||||
it("ignores invalid entries and non-arrays", () => {
|
||||
expect(collectTextContentBlocks(null)).toEqual([]);
|
||||
expect(collectTextContentBlocks([{ type: "text", text: 1 }, undefined, "x"])).toEqual([]);
|
||||
});
|
||||
});
|
||||
16
src/agents/content-blocks.ts
Normal file
16
src/agents/content-blocks.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export function collectTextContentBlocks(content: unknown): string[] {
|
||||
if (!Array.isArray(content)) {
|
||||
return [];
|
||||
}
|
||||
const parts: string[] = [];
|
||||
for (const block of content) {
|
||||
if (!block || typeof block !== "object") {
|
||||
continue;
|
||||
}
|
||||
const rec = block as { type?: unknown; text?: unknown };
|
||||
if (rec.type === "text" && typeof rec.text === "string") {
|
||||
parts.push(rec.text);
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { getChannelPlugin, normalizeChannelId } from "../channels/plugins/index.
|
||||
import { normalizeTargetForProvider } from "../infra/outbound/target-normalization.js";
|
||||
import { MEDIA_TOKEN_RE } from "../media/parse.js";
|
||||
import { truncateUtf16Safe } from "../utils.js";
|
||||
import { collectTextContentBlocks } from "./content-blocks.js";
|
||||
import { type MessagingToolSend } from "./pi-embedded-messaging.js";
|
||||
|
||||
const TOOL_RESULT_MAX_CHARS = 8000;
|
||||
@@ -96,20 +97,9 @@ export function extractToolResultText(result: unknown): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
const record = result as Record<string, unknown>;
|
||||
const content = Array.isArray(record.content) ? record.content : null;
|
||||
if (!content) {
|
||||
return undefined;
|
||||
}
|
||||
const texts = content
|
||||
const texts = collectTextContentBlocks(record.content)
|
||||
.map((item) => {
|
||||
if (!item || typeof item !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
const entry = item as Record<string, unknown>;
|
||||
if (entry.type !== "text" || typeof entry.text !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const trimmed = entry.text.trim();
|
||||
const trimmed = item.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
})
|
||||
.filter((value): value is string => Boolean(value));
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
resolveContextWindowTokens,
|
||||
summarizeInStages,
|
||||
} from "../compaction.js";
|
||||
import { collectTextContentBlocks } from "../content-blocks.js";
|
||||
import { getCompactionSafeguardRuntime } from "./compaction-safeguard-runtime.js";
|
||||
const FALLBACK_SUMMARY =
|
||||
"Summary unavailable due to context limits. Older messages were truncated.";
|
||||
@@ -62,20 +63,7 @@ function formatToolFailureMeta(details: unknown): string | undefined {
|
||||
}
|
||||
|
||||
function extractToolResultText(content: unknown): string {
|
||||
if (!Array.isArray(content)) {
|
||||
return "";
|
||||
}
|
||||
const parts: string[] = [];
|
||||
for (const block of content) {
|
||||
if (!block || typeof block !== "object") {
|
||||
continue;
|
||||
}
|
||||
const rec = block as { type?: unknown; text?: unknown };
|
||||
if (rec.type === "text" && typeof rec.text === "string") {
|
||||
parts.push(rec.text);
|
||||
}
|
||||
}
|
||||
return parts.join("\n");
|
||||
return collectTextContentBlocks(content).join("\n");
|
||||
}
|
||||
|
||||
function collectToolFailures(messages: AgentMessage[]): ToolFailure[] {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { collectTextContentBlocks } from "../../agents/content-blocks.js";
|
||||
import { createOpenClawTools } from "../../agents/openclaw-tools.js";
|
||||
import type { SkillCommandSpec } from "../../agents/skills.js";
|
||||
import { getChannelDock } from "../../channels/dock.js";
|
||||
@@ -62,20 +63,7 @@ function extractTextFromToolResult(result: any): string | null {
|
||||
const trimmed = content.trim();
|
||||
return trimmed ? trimmed : null;
|
||||
}
|
||||
if (!Array.isArray(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts: string[] = [];
|
||||
for (const block of content) {
|
||||
if (!block || typeof block !== "object") {
|
||||
continue;
|
||||
}
|
||||
const rec = block as { type?: unknown; text?: unknown };
|
||||
if (rec.type === "text" && typeof rec.text === "string") {
|
||||
parts.push(rec.text);
|
||||
}
|
||||
}
|
||||
const parts = collectTextContentBlocks(content);
|
||||
const out = parts.join("");
|
||||
const trimmed = out.trim();
|
||||
return trimmed ? trimmed : null;
|
||||
|
||||
Reference in New Issue
Block a user