mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:00:44 +00:00
[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:
committed by
GitHub
parent
61481eb34f
commit
538605ff44
@@ -1,4 +1,4 @@
|
||||
export { resolvePreferredOpenClawTmpDir } from "./src/runtime-api.js";
|
||||
export { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "./src/runtime-api.js";
|
||||
export {
|
||||
definePluginEntry,
|
||||
type AnyAgentTool,
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
|
||||
export { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
||||
|
||||
Reference in New Issue
Block a user