[codex] Extract filesystem safety primitives (#77918)

* refactor: extract filesystem safety primitives

* refactor: use fs-safe for file access helpers

* refactor: reuse fs-safe for media reads

* refactor: use fs-safe for image reads

* refactor: reuse fs-safe in qqbot media opener

* refactor: reuse fs-safe for local media checks

* refactor: consume cleaner fs-safe api

* refactor: align fs-safe json option names

* fix: preserve fs-safe migration contracts

* refactor: use fs-safe primitive subpaths

* refactor: use grouped fs-safe subpaths

* refactor: align fs-safe api usage

* refactor: adapt private state store api

* chore: refresh proof gate

* refactor: follow fs-safe json api split

* refactor: follow reduced fs-safe surface

* build: default fs-safe python helper off

* fix: preserve fs-safe plugin sdk aliases

* refactor: consolidate fs-safe usage

* refactor: unify fs-safe store usage

* refactor: trim fs-safe temp workspace usage

* refactor: hide low-level fs-safe primitives

* build: use published fs-safe package

* fix: preserve outbound recovery durability after rebase

* chore: refresh pr checks
This commit is contained in:
Peter Steinberger
2026-05-06 02:15:17 +01:00
committed by GitHub
parent 61481eb34f
commit 538605ff44
356 changed files with 4918 additions and 11913 deletions

View File

@@ -1,4 +1,4 @@
export { resolvePreferredOpenClawTmpDir } from "./src/runtime-api.js";
export { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "./src/runtime-api.js";
export {
definePluginEntry,
type AnyAgentTool,

View File

@@ -1,9 +1,8 @@
import fs from "node:fs/promises";
import path from "node:path";
import Ajv from "ajv";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import { Type } from "typebox";
import { resolvePreferredOpenClawTmpDir } from "../api.js";
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "../api.js";
import type { OpenClawPluginApi } from "../api.js";
const AjvCtor = Ajv as unknown as typeof import("ajv").default;
@@ -208,78 +207,69 @@ export function createLlmTaskTool(api: OpenClawPluginApi) {
const fullPrompt = `${system}\n\nTASK:\n${prompt}\n\nINPUT_JSON:\n${inputJson}\n`;
let tmpDir: string | null = null;
try {
tmpDir = await fs.mkdtemp(
path.join(resolvePreferredOpenClawTmpDir(), "openclaw-llm-task-"),
);
const sessionId = `llm-task-${Date.now()}`;
const sessionFile = path.join(tmpDir, "session.json");
return await withTempWorkspace(
{ rootDir: resolvePreferredOpenClawTmpDir(), prefix: "openclaw-llm-task-" },
async ({ dir: tmpDir }) => {
const sessionId = `llm-task-${Date.now()}`;
const sessionFile = path.join(tmpDir, "session.json");
const result = await api.runtime.agent.runEmbeddedPiAgent({
sessionId,
sessionFile,
workspaceDir: api.config?.agents?.defaults?.workspace ?? process.cwd(),
config: api.config,
prompt: fullPrompt,
timeoutMs,
runId: `llm-task-${Date.now()}`,
provider,
model,
authProfileId,
authProfileIdSource: authProfileId ? "user" : "auto",
thinkLevel,
streamParams,
disableTools: true,
});
const result = await api.runtime.agent.runEmbeddedPiAgent({
sessionId,
sessionFile,
workspaceDir: api.config?.agents?.defaults?.workspace ?? process.cwd(),
config: api.config,
prompt: fullPrompt,
timeoutMs,
runId: `llm-task-${Date.now()}`,
provider,
model,
authProfileId,
authProfileIdSource: authProfileId ? "user" : "auto",
thinkLevel,
streamParams,
disableTools: true,
});
const text = collectText(
typeof result === "object" && result !== null && "payloads" in result
? (result as { payloads?: Array<{ text?: string; isError?: boolean }> }).payloads
: undefined,
);
if (!text) {
throw new Error("LLM returned empty output");
}
const raw = stripCodeFences(text);
let parsed: unknown;
try {
parsed = JSON.parse(raw);
} catch {
throw new Error("LLM returned invalid JSON");
}
const schema = params.schema;
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
const ajv = new AjvCtor({ allErrors: true, strict: false });
const validate = ajv.compile(schema);
const ok = validate(parsed);
if (!ok) {
const msg =
validate.errors
?.map(
(e: { instancePath?: string; message?: string }) =>
`${e.instancePath || "<root>"} ${e.message || "invalid"}`,
)
.join("; ") ?? "invalid";
throw new Error(`LLM JSON did not match schema: ${msg}`);
const text = collectText(
typeof result === "object" && result !== null && "payloads" in result
? (result as { payloads?: Array<{ text?: string; isError?: boolean }> }).payloads
: undefined,
);
if (!text) {
throw new Error("LLM returned empty output");
}
}
return {
content: [{ type: "text", text: JSON.stringify(parsed, null, 2) }],
details: { json: parsed, provider, model },
};
} finally {
if (tmpDir) {
const raw = stripCodeFences(text);
let parsed: unknown;
try {
await fs.rm(tmpDir, { recursive: true, force: true });
parsed = JSON.parse(raw);
} catch {
// ignore
throw new Error("LLM returned invalid JSON");
}
}
}
const schema = params.schema;
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
const ajv = new AjvCtor({ allErrors: true, strict: false });
const validate = ajv.compile(schema);
const ok = validate(parsed);
if (!ok) {
const msg =
validate.errors
?.map(
(e: { instancePath?: string; message?: string }) =>
`${e.instancePath || "<root>"} ${e.message || "invalid"}`,
)
.join("; ") ?? "invalid";
throw new Error(`LLM JSON did not match schema: ${msg}`);
}
}
return {
content: [{ type: "text", text: JSON.stringify(parsed, null, 2) }],
details: { json: parsed, provider, model },
};
},
);
},
};
}

View File

@@ -1 +1 @@
export { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
export { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";