Files
pikasTech-HWLAB/internal/cloud/code-agent-agentrun-prompt.ts
T

168 lines
7.2 KiB
TypeScript

// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p1-opencode-message-part-authority.
// Responsibility: AgentRun prompt evidence, message-authority text normalization, and prompt hash/preview DTO fields.
import { createHash } from "node:crypto";
import { safeTraceId } from "./server-http-utils.ts";
export function agentRunPromptMetadataFromParams(params = {}, traceId = null) {
return agentRunPromptMetadataFromText(firstNonEmpty(params.message, params.prompt, params.text), traceId, "hwlab-code-agent-request", { fullText: true });
}
export function agentRunPromptMetadataFromSession(session = null, traceId = null) {
const snapshot = session?.session && typeof session.session === "object" ? session.session : null;
const fromTraceResult = agentRunPromptMetadataFromPayload(snapshot?.traceResults?.[traceId], traceId);
if (fromTraceResult) return fromTraceResult;
const messageText = agentRunPromptTextFromMessages(snapshot?.messages, traceId);
if (messageText) return agentRunPromptMetadataFromText(messageText, traceId, "agent-session-owner-message", { fullText: true });
const preview = firstNonEmpty(snapshot?.firstUserMessagePreview);
return preview ? agentRunPromptMetadataFromText(preview, traceId, "agent-session-first-user-preview", { fullText: false }) : null;
}
export function agentRunPromptMetadataFromText(value, traceId = null, source = "hwlab-code-agent-request", options = {}) {
const promptText = promptTextValue(value);
if (!promptText) return null;
return agentRunPromptMetadataFromParts({
traceId,
source,
promptSha256: options.fullText === true ? sha256Text(promptText) : undefined,
promptSummary: promptText,
promptPreview: promptText,
textChars: options.fullText === true ? promptText.length : undefined
});
}
export function agentRunPromptFields(metadata = null) {
if (!metadata) return {};
return compactObject({
promptId: metadata.promptId,
promptSha256: metadata.promptSha256,
promptSummary: metadata.promptSummary,
promptPreview: metadata.promptPreview,
prompt: metadata.prompt
}) ?? {};
}
export function agentRunPromptEventFields(metadata = null) {
if (!metadata) return {};
return compactObject({
promptId: metadata.promptId,
promptSha256: metadata.promptSha256,
promptSummary: metadata.promptSummary,
promptPreview: metadata.promptPreview
}) ?? {};
}
export function messageAuthorityTextValue(value) {
const extracted = promptTextRaw(value).replace(/\r\n?/gu, "\n");
if (!extracted.trim() || extracted.trim() === "[object Object]") return "";
return extracted;
}
function agentRunPromptMetadataFromPayload(payload = null, traceId = null) {
if (!payload || typeof payload !== "object") return null;
const prompt = payload.prompt && typeof payload.prompt === "object" ? payload.prompt : null;
const textValue = firstNonEmpty(prompt?.text, prompt?.summary, prompt?.preview, payload.promptSummary, payload.promptPreview);
const fromText = agentRunPromptMetadataFromText(textValue, traceId, prompt?.source ?? payload.promptSource ?? "agentrun-prompt-metadata", { fullText: Boolean(prompt?.text) });
return agentRunPromptMetadataFromParts({
traceId,
source: prompt?.source ?? payload.promptSource ?? fromText?.prompt?.source ?? "agentrun-prompt-metadata",
promptId: firstNonEmpty(payload.promptId, prompt?.id, fromText?.promptId),
promptSha256: firstNonEmpty(payload.promptSha256, prompt?.sha256, fromText?.promptSha256),
promptSummary: firstNonEmpty(payload.promptSummary, prompt?.summary, fromText?.promptSummary),
promptPreview: firstNonEmpty(payload.promptPreview, prompt?.preview, fromText?.promptPreview),
textChars: Number.isInteger(prompt?.textChars) ? prompt.textChars : fromText?.prompt?.textChars
});
}
function agentRunPromptTextFromMessages(messages = [], traceId = null) {
const list = Array.isArray(messages) ? messages : [];
const resolvedTraceId = safeTraceId(traceId);
const exact = list.find((message) => String(message?.role ?? "").toLowerCase() === "user" && (!resolvedTraceId || safeTraceId(message?.traceId) === resolvedTraceId));
const fallback = list.find((message) => String(message?.role ?? "").toLowerCase() === "user");
return firstNonEmpty(exact?.text, exact?.content, fallback?.text, fallback?.content);
}
function agentRunPromptMetadataFromParts({ traceId = null, source = "hwlab-code-agent-request", promptId = null, promptSha256 = null, promptSummary = null, promptPreview = null, textChars = undefined } = {}) {
const digest = firstNonEmpty(promptSha256);
const summary = clippedPromptText(firstNonEmpty(promptSummary, promptPreview), 240);
const preview = clippedPromptText(firstNonEmpty(promptPreview, promptSummary), 500);
const explicitId = firstNonEmpty(promptId);
if (!explicitId && !digest && !summary && !preview) return null;
const id = explicitId || agentRunPromptId(traceId, digest);
const prompt = compactObject({
id,
sha256: digest || undefined,
summary,
preview,
textChars: Number.isInteger(textChars) ? textChars : undefined,
source,
valuesPrinted: false
});
return compactObject({
promptId: id,
promptSha256: digest || undefined,
promptSummary: summary,
promptPreview: preview,
prompt,
valuesPrinted: false
}) ?? null;
}
function agentRunPromptId(traceId = null, digest = null) {
const traceSuffix = safeTraceId(traceId)?.slice(4).replace(/[^A-Za-z0-9_.:-]/gu, "_");
const digestSuffix = firstNonEmpty(digest)?.slice(0, 16);
const suffix = firstNonEmpty(traceSuffix, digestSuffix);
return suffix ? `prm_${suffix}` : undefined;
}
function clippedPromptText(value, limit) {
const promptText = promptTextValue(value);
if (!promptText) return undefined;
return promptText.length > limit ? `${promptText.slice(0, limit)}...` : promptText;
}
function promptTextValue(value) {
const extracted = promptTextRaw(value).replace(/\s+/gu, " ").trim();
if (!extracted || extracted === "[object Object]") return "";
return extracted;
}
function promptTextRaw(value) {
if (value === undefined || value === null) return "";
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean") return String(value);
if (Array.isArray(value)) return value.map(promptTextRaw).filter(Boolean).join("\n");
if (typeof value === "object") {
for (const key of ["text", "content", "message", "prompt", "value", "summary", "preview", "title"]) {
const text = promptTextRaw(value[key]);
if (text) return text;
}
}
return "";
}
function sha256Text(value) {
return createHash("sha256").update(String(value)).digest("hex");
}
function compactObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
const result = {};
for (const [key, item] of Object.entries(value)) {
if (item === undefined || item === null) continue;
if (Array.isArray(item) && item.length === 0) continue;
if (typeof item === "object" && !Array.isArray(item) && Object.keys(item).length === 0) continue;
result[key] = item;
}
return Object.keys(result).length > 0 ? result : undefined;
}
function firstNonEmpty(...values) {
for (const value of values) {
const text = String(value ?? "").trim();
if (text) return text;
}
return null;
}