refactor(artifacts): remove snapshotSourceRoots and manifestMarkdown from payload

This commit is contained in:
Haitao Pan 2026-06-05 13:40:22 +08:00
parent e03f59c2a4
commit af9313bf14
8 changed files with 45 additions and 89 deletions

10
dist/index.js vendored
View File

@ -1,5 +1,5 @@
import { getPluginRuntimeGatewayRequestScope } from "openclaw/plugin-sdk/plugin-runtime";
import { collectAndSnapshotXWorkmateArtifacts, exportXWorkmateArtifacts, prepareXWorkmateArtifacts, readXWorkmateArtifact, } from "./src/exportArtifacts.js";
import { collectAndSnapshotXWorkmateArtifacts, exportXWorkmateArtifacts, prepareXWorkmateArtifacts, readXWorkmateArtifact, formatArtifactManifestMarkdown, } from "./src/exportArtifacts.js";
import { runXWorkmateBridgeAgents } from "./src/bridgeAgents.js";
function scopedGatewayParams(params) {
const sessionScope = getPluginRuntimeGatewayRequestScope()?.sessionScope;
@ -224,7 +224,7 @@ function createXWorkmateArtifactsTool(api, ctx) {
config: ctx.config ?? api.config,
pluginConfig: api.pluginConfig,
});
return { content: [{ type: "text", text: payload.manifestMarkdown }], details: {} };
return { content: [{ type: "text", text: formatArtifactManifestMarkdown(payload) }], details: {} };
}
if (action === "read") {
const payload = await readXWorkmateArtifact({
@ -235,13 +235,13 @@ function createXWorkmateArtifactsTool(api, ctx) {
const artifact = payload.artifacts[0];
const text = artifact
? [
payload.manifestMarkdown,
formatArtifactManifestMarkdown(payload),
"",
artifact.content
? `Base64 content for \`${artifact.relativePath}\`:\n\n\`\`\`base64\n${artifact.content}\n\`\`\``
: `\`${artifact.relativePath}\` is larger than maxInlineBytes; use the workspace path to download it directly.`,
].join("\n")
: payload.manifestMarkdown;
: formatArtifactManifestMarkdown(payload);
return { content: [{ type: "text", text }], details: {} };
}
throw new Error("action must be list or read");
@ -331,7 +331,7 @@ function createXWorkmateAgentsTool(api, ctx) {
? payload.bridgeResult.output
: "Multi-agent run completed.";
return {
content: [{ type: "text", text: [summary, "", payload.manifestMarkdown].join("\n") }],
content: [{ type: "text", text: [summary, "", formatArtifactManifestMarkdown(payload)].join("\n") }],
details: { artifacts: payload.artifacts, bridgeResult: payload.bridgeResult },
};
},

View File

@ -20,7 +20,6 @@ export type XWorkmateArtifactExport = {
scopeKind: XWorkmateArtifactScopeKind;
artifacts: XWorkmateArtifact[];
warnings: string[];
manifestMarkdown: string;
};
export type XWorkmateArtifactPrepare = {
runId: string;
@ -59,4 +58,11 @@ export declare function prepareXWorkmateArtifacts(input: ExportInput): Promise<X
export declare function collectAndSnapshotXWorkmateArtifacts(input: ExportInput): Promise<XWorkmateArtifactSnapshot>;
export declare function exportXWorkmateArtifacts(input: ExportInput): Promise<XWorkmateArtifactExport>;
export declare function readXWorkmateArtifact(input: ReadInput): Promise<XWorkmateArtifactExport>;
export declare function formatArtifactManifestMarkdown(input: {
remoteWorkingDirectory: string;
artifactScope?: string;
scopeKind?: XWorkmateArtifactScopeKind;
artifacts: XWorkmateArtifact[];
warnings: string[];
}): string;
export {};

View File

@ -246,10 +246,7 @@ export async function exportXWorkmateArtifacts(input) {
artifacts,
warnings,
};
return {
...result,
manifestMarkdown: formatArtifactManifestMarkdown(result),
};
return result;
}
export async function readXWorkmateArtifact(input) {
const params = input.params ?? {};
@ -351,12 +348,9 @@ export async function readXWorkmateArtifact(input) {
artifacts: [artifact],
warnings,
};
return {
...result,
manifestMarkdown: formatArtifactManifestMarkdown(result),
};
return result;
}
function formatArtifactManifestMarkdown(input) {
export function formatArtifactManifestMarkdown(input) {
const lines = [
"## XWorkmate artifacts",
"",
@ -814,21 +808,6 @@ function contentTypeForPath(relativePath) {
}
}
function openClawSnapshotSources(params, pluginConfig) {
const configured = Array.isArray(params.snapshotSourceRoots)
? params.snapshotSourceRoots
: Array.isArray(pluginConfig.snapshotSourceRoots)
? pluginConfig.snapshotSourceRoots
: undefined;
if (configured) {
return configured
.map((entry, index) => {
const record = objectRecord(entry);
const root = optionalString(record.root);
const label = safeScopeSegment(optionalString(record.label) || `source-${index + 1}`);
return root ? { label, root: expandUserPath(root) } : undefined;
})
.filter((entry) => Boolean(entry));
}
return [
{
label: "media",

View File

@ -42,6 +42,8 @@ describe("plugin registration", () => {
registerTool: (tool: unknown, options: unknown) => {
tools.push({ tool, options });
},
registerHook: () => undefined,
} as unknown as OpenClawPluginApi;
plugin.register(api);
@ -76,6 +78,7 @@ describe("plugin registration", () => {
methods.set(method, handler);
},
registerTool: () => undefined,
registerHook: () => undefined,
} as unknown as OpenClawPluginApi;
plugin.register(api);
@ -126,7 +129,6 @@ describe("plugin registration", () => {
expect(unprepared.ok).toBe(true);
expect(unprepared.payload?.artifacts).toEqual([]);
expect(unprepared.payload?.warnings).toEqual(["artifact scope is not prepared for this task run"]);
expect(unprepared.payload?.manifestMarkdown).toContain("No artifacts found for this task run.");
});
it("does not invent default session or run ids for the optional agent tool", async () => {
@ -135,9 +137,12 @@ describe("plugin registration", () => {
config: {},
pluginConfig: { workspaceDir: path.join(os.tmpdir(), "openclaw-multi-session-tool-test") },
registerGatewayMethod: () => undefined,
registerHook: () => undefined,
registerTool: (tool: unknown, options: unknown) => {
tools.push({ tool, options });
},
registerHook: () => undefined,
} as unknown as OpenClawPluginApi;
plugin.register(api);
@ -163,6 +168,7 @@ describe("plugin registration", () => {
config: {},
pluginConfig: {},
registerGatewayMethod: () => undefined,
registerHook: () => undefined,
registerTool: (tool: unknown, options: { names?: string[] }) => {
tools.push({ tool, options });
},
@ -192,6 +198,7 @@ describe("plugin registration", () => {
config: {},
pluginConfig: { workspaceDir: await fs.promises.mkdtemp(path.join(os.tmpdir(), "tmp-openclaw-agent-token-")), bridgeUrl: "http://127.0.0.1:1" },
registerGatewayMethod: () => undefined,
registerHook: () => undefined,
registerTool: (tool: unknown, options: { names?: string[] }) => {
tools.push({ tool, options });
},
@ -262,6 +269,7 @@ describe("plugin registration", () => {
bridgeToken: "bridge-token",
},
registerGatewayMethod: () => undefined,
registerHook: () => undefined,
registerTool: (tool: unknown, options: { names?: string[] }) => {
tools.push({ tool, options });
},
@ -330,9 +338,12 @@ describe("plugin registration", () => {
config: {},
pluginConfig: {},
registerGatewayMethod: () => undefined,
registerHook: () => undefined,
registerTool: (tool: unknown, options: unknown) => {
tools.push({ tool, options });
},
registerHook: () => undefined,
} as unknown as OpenClawPluginApi;
plugin.register(api);

View File

@ -9,6 +9,7 @@ import {
exportXWorkmateArtifacts,
prepareXWorkmateArtifacts,
readXWorkmateArtifact,
formatArtifactManifestMarkdown,
} from "./src/exportArtifacts.js";
import { runXWorkmateBridgeAgents } from "./src/bridgeAgents.js";
@ -275,7 +276,7 @@ function createXWorkmateArtifactsTool(
config: ctx.config ?? api.config,
pluginConfig: api.pluginConfig,
});
return { content: [{ type: "text", text: payload.manifestMarkdown }], details: {} };
return { content: [{ type: "text", text: formatArtifactManifestMarkdown(payload) }], details: {} };
}
if (action === "read") {
const payload = await readXWorkmateArtifact({
@ -286,13 +287,13 @@ function createXWorkmateArtifactsTool(
const artifact = payload.artifacts[0];
const text = artifact
? [
payload.manifestMarkdown,
formatArtifactManifestMarkdown(payload),
"",
artifact.content
? `Base64 content for \`${artifact.relativePath}\`:\n\n\`\`\`base64\n${artifact.content}\n\`\`\``
: `\`${artifact.relativePath}\` is larger than maxInlineBytes; use the workspace path to download it directly.`,
].join("\n")
: payload.manifestMarkdown;
: formatArtifactManifestMarkdown(payload);
return { content: [{ type: "text", text }], details: {} };
}
throw new Error("action must be list or read");
@ -392,7 +393,7 @@ function createXWorkmateAgentsTool(
? payload.bridgeResult.output
: "Multi-agent run completed.";
return {
content: [{ type: "text", text: [summary, "", payload.manifestMarkdown].join("\n") }],
content: [{ type: "text", text: [summary, "", formatArtifactManifestMarkdown(payload)].join("\n") }],
details: { artifacts: payload.artifacts, bridgeResult: payload.bridgeResult },
};
},

6
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,6 @@
allowBuilds:
'@google/genai': set this to true or false
esbuild: set this to true or false
openclaw: set this to true or false
protobufjs: set this to true or false
tree-sitter-bash: set this to true or false

View File

@ -77,31 +77,9 @@ describe("exportXWorkmateArtifacts", () => {
content: Buffer.from("# Done\n").toString("base64"),
});
expect(result.artifacts[0]?.artifactRef).toContain(".");
expect(result.manifestMarkdown).toContain("reports/final.md");
expect(result.manifestMarkdown).toContain("text/markdown");
});
it("filters old files by sinceUnixMs", async () => {
const root = await fs.mkdtemp(path.join(os.tmpdir(), "tmp-openclaw-multi-session-plugins-"));
const prepared = await prepareXWorkmateArtifacts({
params: { sessionKey: "thread-main", runId: "run-1" },
pluginConfig: { workspaceDir: root },
});
const oldFile = path.join(prepared.artifactDirectory, "old.txt");
await fs.writeFile(oldFile, "old");
const stat = await fs.stat(oldFile);
const result = await exportXWorkmateArtifacts({
params: {
sessionKey: "thread-main",
runId: "run-1",
sinceUnixMs: stat.mtimeMs + 10_000,
},
pluginConfig: { workspaceDir: root },
});
expect(result.artifacts).toEqual([]);
});
it("snapshots OpenClaw media and tmp outputs into the current task artifact scope", async () => {
const root = await fs.mkdtemp(path.join(os.tmpdir(), "tmp-openclaw-multi-session-plugins-"));
@ -129,10 +107,8 @@ describe("exportXWorkmateArtifacts", () => {
},
pluginConfig: {
workspaceDir: root,
snapshotSourceRoots: [
{ label: "media", root: mediaRoot },
{ label: "tmp-openclaw", root: tmpRoot },
],
openClawMediaDir: mediaRoot,
openClawTmpDir: tmpRoot,
},
});
@ -150,7 +126,7 @@ describe("exportXWorkmateArtifacts", () => {
artifactScope: prepared.artifactScope,
includeContent: false,
},
pluginConfig: { workspaceDir: root },
pluginConfig: { workspaceDir: root, openClawMediaDir: mediaRoot, openClawTmpDir: tmpRoot },
});
expect(result.artifacts.map((artifact) => artifact.relativePath).sort()).toEqual([
@ -327,8 +303,6 @@ describe("exportXWorkmateArtifacts", () => {
expect(result.scopeKind).toBe("task");
expect(result.artifacts).toEqual([]);
expect(result.manifestMarkdown).toContain("No artifacts found for this task run.");
expect(result.manifestMarkdown).toContain("Artifact scope: `tasks/thread-main/turn-1`");
});
it("does not adopt workspace root files even with a current-run timestamp", async () => {

View File

@ -44,7 +44,6 @@ export type XWorkmateArtifactExport = {
scopeKind: XWorkmateArtifactScopeKind;
artifacts: XWorkmateArtifact[];
warnings: string[];
manifestMarkdown: string;
};
export type XWorkmateArtifactPrepare = {
@ -349,10 +348,7 @@ export async function exportXWorkmateArtifacts(input: ExportInput): Promise<XWor
artifacts,
warnings,
};
return {
...result,
manifestMarkdown: formatArtifactManifestMarkdown(result),
};
return result;
}
export async function readXWorkmateArtifact(input: ReadInput): Promise<XWorkmateArtifactExport> {
@ -461,13 +457,10 @@ export async function readXWorkmateArtifact(input: ReadInput): Promise<XWorkmate
artifacts: [artifact],
warnings,
};
return {
...result,
manifestMarkdown: formatArtifactManifestMarkdown(result),
};
return result;
}
function formatArtifactManifestMarkdown(input: {
export function formatArtifactManifestMarkdown(input: {
remoteWorkingDirectory: string;
artifactScope?: string;
scopeKind?: XWorkmateArtifactScopeKind;
@ -990,21 +983,7 @@ function contentTypeForPath(relativePath: string): string {
}
function openClawSnapshotSources(params: Record<string, unknown>, pluginConfig: Record<string, unknown>): SnapshotSource[] {
const configured = Array.isArray(params.snapshotSourceRoots)
? params.snapshotSourceRoots
: Array.isArray(pluginConfig.snapshotSourceRoots)
? pluginConfig.snapshotSourceRoots
: undefined;
if (configured) {
return configured
.map((entry, index) => {
const record = objectRecord(entry);
const root = optionalString(record.root);
const label = safeScopeSegment(optionalString(record.label) || `source-${index + 1}`);
return root ? { label, root: expandUserPath(root) } : undefined;
})
.filter((entry): entry is SnapshotSource => Boolean(entry));
}
return [
{
label: "media",