fix: expose code agent prompt metadata
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
|
||||
import { defaultCodeAgentTraceStore } from "./code-agent-trace-store.ts";
|
||||
import { decorateCodeAgentSession } from "./code-agent-session-lifecycle.ts";
|
||||
@@ -215,6 +215,7 @@ export function initialAgentRunChatResult({ params = {}, options = {}, traceId }
|
||||
const env = options.env ?? process.env;
|
||||
const timestamp = nowIso(options.now);
|
||||
const backendProfile = resolveAgentRunBackendProfile(env, params);
|
||||
const promptEvidence = agentRunPromptMetadataFromParams(params, traceId);
|
||||
return {
|
||||
accepted: true,
|
||||
status: "running",
|
||||
@@ -234,6 +235,7 @@ export function initialAgentRunChatResult({ params = {}, options = {}, traceId }
|
||||
sessionMode: AGENTRUN_SESSION_MODE,
|
||||
implementationType: AGENTRUN_IMPLEMENTATION_TYPE,
|
||||
threadContinuityPolicy: THREAD_CONTINUITY_POLICY,
|
||||
...agentRunPromptFields(promptEvidence),
|
||||
agentRun: {
|
||||
adapter: ADAPTER_ID,
|
||||
status: "pending-dispatch",
|
||||
@@ -257,6 +259,7 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
|
||||
const startedAt = nowIso(options.now);
|
||||
const ownerApiKey = await resolveOwnerApiKey({ params, options, now: () => nowIso(options.now) });
|
||||
const toolCapabilities = await resolveToolCapabilities({ params, options });
|
||||
const promptEvidence = agentRunPromptMetadataFromParams(params, traceId);
|
||||
|
||||
traceStore.ensure(traceId, agentRunTraceMeta(env, params));
|
||||
traceStore.append(traceId, {
|
||||
@@ -267,6 +270,7 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
|
||||
waitingFor: "agentrun-run-reuse-or-create",
|
||||
adapter: ADAPTER_ID,
|
||||
managerHost: new URL(managerUrl).hostname,
|
||||
...agentRunPromptEventFields(promptEvidence),
|
||||
valuesPrinted: false
|
||||
}, agentRunTraceMeta(env, params));
|
||||
|
||||
@@ -674,6 +678,7 @@ export async function loadPersistedAgentRunResult(traceId, options = {}) {
|
||||
if (!agentRun?.runId) return null;
|
||||
const backendProfile = firstNonEmpty(agentRun.backendProfile, "deepseek");
|
||||
const status = firstNonEmpty(session?.status === "canceled" ? "canceled" : null, agentRun.terminalStatus, agentRun.commandState, agentRun.status, "running");
|
||||
const promptEvidence = agentRunPromptMetadataFromSession(session, safeId);
|
||||
return {
|
||||
accepted: true,
|
||||
status,
|
||||
@@ -683,6 +688,7 @@ export async function loadPersistedAgentRunResult(traceId, options = {}) {
|
||||
sessionId: safeSessionId(session?.id) || agentRun.sessionId || null,
|
||||
threadId: safeOpaqueId(session?.threadId) || agentRun.threadId || null,
|
||||
messageId: `msg_${safeId.slice(4)}`,
|
||||
...agentRunPromptFields(promptEvidence),
|
||||
createdAt: session?.startedAt ?? session?.updatedAt ?? nowIso(options.now),
|
||||
updatedAt: session?.updatedAt ?? nowIso(options.now),
|
||||
ownerUserId: session?.ownerUserId,
|
||||
@@ -879,6 +885,121 @@ function rejectRemovedResourceWorkspaceFiles(value) {
|
||||
throw adapterError("legacy_workspace_files_removed", "workspaceFiles/resourceWorkspaceFiles are removed; use AgentRun ResourceBundleRef kind=gitbundle with bundles[]");
|
||||
}
|
||||
|
||||
function agentRunPromptMetadataFromParams(params = {}, traceId = null) {
|
||||
return agentRunPromptMetadataFromText(firstNonEmpty(params.message, params.prompt, params.text), traceId, "hwlab-code-agent-request", { fullText: true });
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 agentRunPromptMetadataFromText(value, traceId = null, source = "hwlab-code-agent-request", options = {}) {
|
||||
const promptText = String(value ?? "").trim();
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
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 agentRunPromptFields(metadata = null) {
|
||||
if (!metadata) return {};
|
||||
return compactObject({
|
||||
promptId: metadata.promptId,
|
||||
promptSha256: metadata.promptSha256,
|
||||
promptSummary: metadata.promptSummary,
|
||||
promptPreview: metadata.promptPreview,
|
||||
prompt: metadata.prompt
|
||||
}) ?? {};
|
||||
}
|
||||
|
||||
function agentRunPromptEventFields(metadata = null) {
|
||||
if (!metadata) return {};
|
||||
return compactObject({
|
||||
promptId: metadata.promptId,
|
||||
promptSha256: metadata.promptSha256,
|
||||
promptSummary: metadata.promptSummary,
|
||||
promptPreview: metadata.promptPreview
|
||||
}) ?? {};
|
||||
}
|
||||
|
||||
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 = String(value ?? "").trim();
|
||||
if (!promptText) return undefined;
|
||||
return promptText.length > limit ? `${promptText.slice(0, limit)}...` : promptText;
|
||||
}
|
||||
|
||||
function sha256Text(value) {
|
||||
return createHash("sha256").update(String(value)).digest("hex");
|
||||
}
|
||||
|
||||
function adapterError(code, message, details = {}) {
|
||||
return Object.assign(new Error(message), {
|
||||
code,
|
||||
@@ -889,12 +1010,15 @@ function adapterError(code, message, details = {}) {
|
||||
|
||||
function buildAgentRunCommandInput({ params, traceId, backendProfile, sessionId }) {
|
||||
const prompt = String(params.message ?? params.prompt ?? "").trim();
|
||||
const promptEvidence = agentRunPromptMetadataFromText(prompt, traceId, "agentrun-command-payload", { fullText: true });
|
||||
const threadId = safeOpaqueId(params.threadId);
|
||||
return {
|
||||
type: "turn",
|
||||
payload: {
|
||||
prompt,
|
||||
message: prompt,
|
||||
...agentRunPromptEventFields(promptEvidence),
|
||||
...(promptEvidence?.prompt ? { promptMetadata: promptEvidence.prompt } : {}),
|
||||
traceId,
|
||||
projectId: firstNonEmpty(params.projectId) || null,
|
||||
conversationId: safeConversationId(params.conversationId) || null,
|
||||
@@ -913,12 +1037,15 @@ function buildAgentRunCommandInput({ params, traceId, backendProfile, sessionId
|
||||
|
||||
function buildAgentRunSteerCommandInput({ params, traceId, steerTraceId, mapped }) {
|
||||
const prompt = String(params.message ?? params.prompt ?? params.text ?? "").trim();
|
||||
const promptEvidence = agentRunPromptMetadataFromText(prompt, steerTraceId, "agentrun-steer-command-payload", { fullText: true });
|
||||
return {
|
||||
type: "steer",
|
||||
payload: {
|
||||
prompt,
|
||||
message: prompt,
|
||||
text: prompt,
|
||||
...agentRunPromptEventFields(promptEvidence),
|
||||
...(promptEvidence?.prompt ? { promptMetadata: promptEvidence.prompt } : {}),
|
||||
traceId: steerTraceId,
|
||||
targetTraceId: traceId,
|
||||
targetCommandId: mapped.agentRun.commandId,
|
||||
|
||||
Reference in New Issue
Block a user