style(agents): normalize runtime prompt formatting

This commit is contained in:
Peter Steinberger
2026-04-04 12:19:00 +01:00
parent c70b10460c
commit 1037af01ad
8 changed files with 42 additions and 54 deletions

View File

@@ -45,9 +45,9 @@ vi.mock("./remote-media.js", () => ({
}));
import { fetchWithSsrFGuard } from "../../runtime-api.js";
import { downloadMSTeamsGraphMedia } from "./graph.js";
import { downloadAndStoreMSTeamsRemoteMedia } from "./remote-media.js";
import { safeFetchWithPolicy } from "./shared.js";
import { downloadMSTeamsGraphMedia } from "./graph.js";
function mockFetchResponse(body: unknown, status = 200) {
const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
@@ -279,35 +279,37 @@ describe("downloadMSTeamsGraphMedia hosted content $value fallback", () => {
});
it("adds the OpenClaw User-Agent to guarded Graph attachment fetches", async () => {
vi.mocked(fetchWithSsrFGuard).mockImplementation(async (params: { url: string; init?: RequestInit }) => {
const url = params.url;
if (url.endsWith("/messages/msg-ua") && !url.includes("hostedContents")) {
vi.mocked(fetchWithSsrFGuard).mockImplementation(
async (params: { url: string; init?: RequestInit }) => {
const url = params.url;
if (url.endsWith("/messages/msg-ua") && !url.includes("hostedContents")) {
return {
response: mockFetchResponse({ body: {}, attachments: [] }),
release: async () => {},
finalUrl: params.url,
};
}
if (url.endsWith("/hostedContents")) {
return {
response: mockFetchResponse({ value: [] }),
release: async () => {},
finalUrl: params.url,
};
}
if (url.endsWith("/attachments")) {
return {
response: mockFetchResponse({ value: [] }),
release: async () => {},
finalUrl: params.url,
};
}
return {
response: mockFetchResponse({ body: {}, attachments: [] }),
response: mockFetchResponse({}, 404),
release: async () => {},
finalUrl: params.url,
};
}
if (url.endsWith("/hostedContents")) {
return {
response: mockFetchResponse({ value: [] }),
release: async () => {},
finalUrl: params.url,
};
}
if (url.endsWith("/attachments")) {
return {
response: mockFetchResponse({ value: [] }),
release: async () => {},
finalUrl: params.url,
};
}
return {
response: mockFetchResponse({}, 404),
release: async () => {},
finalUrl: params.url,
};
});
},
);
await downloadMSTeamsGraphMedia({
messageUrl: "https://graph.microsoft.com/v1.0/chats/c/messages/msg-ua",

View File

@@ -13,12 +13,7 @@ describe("prompt cache observability", () => {
it("collects trimmed tool names only", () => {
expect(
collectPromptCacheToolNames([
{ name: " read " },
{ name: "" },
{},
{ name: "write" },
]),
collectPromptCacheToolNames([{ name: " read " }, { name: "" }, {}, { name: "write" }]),
).toEqual(["read", "write"]);
});

View File

@@ -130,9 +130,7 @@ function diffSnapshots(
}
export function collectPromptCacheToolNames(tools: Array<{ name?: string }>): string[] {
return tools
.map((tool) => tool.name?.trim())
.filter((name): name is string => Boolean(name));
return tools.map((tool) => tool.name?.trim()).filter((name): name is string => Boolean(name));
}
export function beginPromptCacheObservation(params: {

View File

@@ -1,8 +1,8 @@
import type { StreamFn } from "@mariozechner/pi-agent-core";
import { streamSimple } from "@mariozechner/pi-ai";
import type { ThinkLevel } from "../../auto-reply/thinking.js";
import { resolveProviderRequestPolicy } from "../provider-attribution.js";
import { isProxyReasoningUnsupportedModelHint } from "../../plugin-sdk/provider-model-shared.js";
import { resolveProviderRequestPolicy } from "../provider-attribution.js";
import { resolveProviderRequestPolicyConfig } from "../provider-request-config.js";
import { applyAnthropicEphemeralCacheControlMarkers } from "./anthropic-cache-control-payload.js";
import { isAnthropicModelRef } from "./anthropic-family-cache-semantics.js";

View File

@@ -26,10 +26,7 @@ import {
resolveFailoverStatus,
} from "../failover-error.js";
import { LiveSessionModelSwitchError } from "../live-model-switch-error.js";
import {
shouldSwitchToLiveModel,
clearLiveModelSwitchPending,
} from "../live-model-switch.js";
import { shouldSwitchToLiveModel, clearLiveModelSwitchPending } from "../live-model-switch.js";
import {
applyAuthHeaderOverride,
applyLocalNoAuthHeaderOverride,

View File

@@ -20,10 +20,9 @@ export function composeSystemPromptWithHookContext(params: {
if (!prependSystem && !appendSystem) {
return undefined;
}
return joinPresentTextSegments(
[prependSystem, params.baseSystemPrompt, appendSystem],
{ trim: true },
);
return joinPresentTextSegments([prependSystem, params.baseSystemPrompt, appendSystem], {
trim: true,
});
}
export function resolveAttemptSpawnWorkspaceDir(params: {

View File

@@ -1,5 +1,8 @@
export function normalizeStructuredPromptSection(text: string): string {
return text.replace(/\r\n?/g, "\n").replace(/[ \t]+$/gm, "").trim();
return text
.replace(/\r\n?/g, "\n")
.replace(/[ \t]+$/gm, "")
.trim();
}
export function normalizePromptCapabilityIds(capabilities: ReadonlyArray<string>): string[] {

View File

@@ -387,9 +387,7 @@ export function buildAgentSystemPrompt(params: {
const runtimeChannel = runtimeInfo?.channel?.trim().toLowerCase();
const runtimeCapabilities = runtimeInfo?.capabilities ?? [];
const runtimeCapabilitiesLower = new Set(
runtimeCapabilities
.map((cap) => String(cap).trim().toLowerCase())
.filter(Boolean),
runtimeCapabilities.map((cap) => String(cap).trim().toLowerCase()).filter(Boolean),
);
const inlineButtonsEnabled = runtimeCapabilitiesLower.has("inlinebuttons");
const messageChannelOptions = listDeliverableMessageChannels().join("|");
@@ -519,15 +517,11 @@ export function buildAgentSystemPrompt(params: {
hasGateway && !isMinimal ? "" : "",
"",
// Skip model aliases for subagent/none modes
modelAliasLines.length > 0 && !isMinimal
? "## Model Aliases"
: "",
modelAliasLines.length > 0 && !isMinimal ? "## Model Aliases" : "",
modelAliasLines.length > 0 && !isMinimal
? "Prefer aliases when specifying model overrides; full provider/model is also accepted."
: "",
modelAliasLines.length > 0 && !isMinimal
? modelAliasLines.join("\n")
: "",
modelAliasLines.length > 0 && !isMinimal ? modelAliasLines.join("\n") : "",
modelAliasLines.length > 0 && !isMinimal ? "" : "",
userTimezone
? "If you need the current date, time, or day of week, run session_status (📊 session_status)."