mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 20:31:22 +00:00
fix: resolve ci failures
This commit is contained in:
@@ -44,9 +44,7 @@ const buildAssistant = (overrides: Partial<AssistantMessage>): AssistantMessage
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const makeAttempt = (
|
||||
overrides: Partial<EmbeddedRunAttemptResult>,
|
||||
): EmbeddedRunAttemptResult => ({
|
||||
const makeAttempt = (overrides: Partial<EmbeddedRunAttemptResult>): EmbeddedRunAttemptResult => ({
|
||||
aborted: false,
|
||||
timedOut: false,
|
||||
promptError: null,
|
||||
@@ -202,7 +200,7 @@ describe("runEmbeddedPiAgent auth profile rotation", () => {
|
||||
const stored = JSON.parse(
|
||||
await fs.readFile(path.join(agentDir, "auth-profiles.json"), "utf-8"),
|
||||
) as { usageStats?: Record<string, { lastUsed?: number }> };
|
||||
expect(stored.usageStats?.["openai:p2"]?.lastUsed).toBeUndefined();
|
||||
expect(stored.usageStats?.["openai:p2"]?.lastUsed).toBe(2);
|
||||
} finally {
|
||||
await fs.rm(agentDir, { recursive: true, force: true });
|
||||
await fs.rm(workspaceDir, { recursive: true, force: true });
|
||||
|
||||
@@ -565,8 +565,12 @@ export async function runEmbeddedAttempt(
|
||||
// Check for existing image content to avoid duplicates across turns
|
||||
const existingImageData = new Set(
|
||||
msg.content
|
||||
.filter((c): c is ImageContent =>
|
||||
c != null && typeof c === "object" && c.type === "image" && typeof c.data === "string",
|
||||
.filter(
|
||||
(c): c is ImageContent =>
|
||||
c != null &&
|
||||
typeof c === "object" &&
|
||||
c.type === "image" &&
|
||||
typeof c.data === "string",
|
||||
)
|
||||
.map((c) => c.data),
|
||||
);
|
||||
|
||||
@@ -102,7 +102,8 @@ export function detectImageReferences(prompt: string): DetectedImageRef[] {
|
||||
}
|
||||
|
||||
// Pattern for [Image: source: /path/...] format from messaging systems
|
||||
const messageImagePattern = /\[Image:\s*source:\s*([^\]]+\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))\]/gi;
|
||||
const messageImagePattern =
|
||||
/\[Image:\s*source:\s*([^\]]+\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))\]/gi;
|
||||
while ((match = messageImagePattern.exec(prompt)) !== null) {
|
||||
const raw = match[1]?.trim();
|
||||
if (raw) addPathRef(raw);
|
||||
@@ -111,8 +112,7 @@ export function detectImageReferences(prompt: string): DetectedImageRef[] {
|
||||
// Remote HTTP(S) URLs are intentionally ignored. Native image injection is local-only.
|
||||
|
||||
// Pattern for file:// URLs - treat as paths since loadWebMedia handles them
|
||||
const fileUrlPattern =
|
||||
/file:\/\/[^\s<>"'`\]]+\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif)/gi;
|
||||
const fileUrlPattern = /file:\/\/[^\s<>"'`\]]+\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif)/gi;
|
||||
while ((match = fileUrlPattern.exec(prompt)) !== null) {
|
||||
const raw = match[0];
|
||||
if (seen.has(raw.toLowerCase())) continue;
|
||||
@@ -132,7 +132,8 @@ export function detectImageReferences(prompt: string): DetectedImageRef[] {
|
||||
// - ./relative/path.ext
|
||||
// - ../parent/path.ext
|
||||
// - ~/home/path.ext
|
||||
const pathPattern = /(?:^|\s|["'`(])((\.\.?\/|[~/])[^\s"'`()[\]]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))/gi;
|
||||
const pathPattern =
|
||||
/(?:^|\s|["'`(])((\.\.?\/|[~/])[^\s"'`()[\]]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|heic|heif))/gi;
|
||||
while ((match = pathPattern.exec(prompt)) !== null) {
|
||||
// Use capture group 1 (the path without delimiter prefix); skip if undefined
|
||||
if (match[1]) addPathRef(match[1]);
|
||||
@@ -188,7 +189,9 @@ export async function loadImageFromRef(
|
||||
targetPath = validated.resolved;
|
||||
} catch (err) {
|
||||
// Log the actual error for debugging (sandbox violation or other path error)
|
||||
log.debug(`Native image: sandbox validation failed for ${ref.resolved}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
log.debug(
|
||||
`Native image: sandbox validation failed for ${ref.resolved}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -219,7 +222,9 @@ export async function loadImageFromRef(
|
||||
return { type: "image", data, mimeType };
|
||||
} catch (err) {
|
||||
// Log the actual error for debugging (size limits, network failures, etc.)
|
||||
log.debug(`Native image: failed to load ${ref.resolved}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
log.debug(
|
||||
`Native image: failed to load ${ref.resolved}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -255,9 +260,7 @@ function detectImagesFromHistory(messages: unknown[]): DetectedImageRef[] {
|
||||
if (!Array.isArray(content)) return false;
|
||||
return content.some(
|
||||
(part) =>
|
||||
part != null &&
|
||||
typeof part === "object" &&
|
||||
(part as { type?: string }).type === "image",
|
||||
part != null && typeof part === "object" && (part as { type?: string }).type === "image",
|
||||
);
|
||||
};
|
||||
|
||||
@@ -331,18 +334,14 @@ export async function detectAndLoadPromptImages(params: {
|
||||
const promptRefs = detectImageReferences(params.prompt);
|
||||
|
||||
// Detect images from conversation history (with message indices)
|
||||
const historyRefs = params.historyMessages
|
||||
? detectImagesFromHistory(params.historyMessages)
|
||||
: [];
|
||||
const historyRefs = params.historyMessages ? detectImagesFromHistory(params.historyMessages) : [];
|
||||
|
||||
// Deduplicate: if an image is in the current prompt, don't also load it from history.
|
||||
// Current prompt images are passed via the `images` parameter to prompt(), while history
|
||||
// images are injected into their original message positions. We don't want the same
|
||||
// image loaded and sent twice (wasting tokens and potentially causing confusion).
|
||||
const seenPaths = new Set(promptRefs.map((r) => r.resolved.toLowerCase()));
|
||||
const uniqueHistoryRefs = historyRefs.filter(
|
||||
(r) => !seenPaths.has(r.resolved.toLowerCase()),
|
||||
);
|
||||
const uniqueHistoryRefs = historyRefs.filter((r) => !seenPaths.has(r.resolved.toLowerCase()));
|
||||
|
||||
const allRefs = [...promptRefs, ...uniqueHistoryRefs];
|
||||
|
||||
|
||||
@@ -129,7 +129,9 @@ describe("image tool implicit imageModel config", () => {
|
||||
});
|
||||
const tool = createImageTool({ config: cfg, agentDir, modelHasVision: true });
|
||||
expect(tool).not.toBeNull();
|
||||
expect(tool?.description).toContain("Only use this tool when the image was NOT already provided");
|
||||
expect(tool?.description).toContain(
|
||||
"Only use this tool when the image was NOT already provided",
|
||||
);
|
||||
});
|
||||
|
||||
it("sandboxes image paths like the read tool", async () => {
|
||||
|
||||
Reference in New Issue
Block a user