fix: sanitize user-facing errors and strip final tags
Co-authored-by: Drake Thomsen <drake.thomsen@example.com>
This commit is contained in:
@@ -419,14 +419,33 @@ export async function runEmbeddedAttempt(
|
||||
try {
|
||||
const promptStartedAt = Date.now();
|
||||
log.debug(`embedded run prompt start: runId=${params.runId} sessionId=${params.sessionId}`);
|
||||
try {
|
||||
await activeSession.prompt(params.prompt, { images: params.images });
|
||||
} catch (err) {
|
||||
promptError = err;
|
||||
} finally {
|
||||
log.debug(
|
||||
`embedded run prompt end: runId=${params.runId} sessionId=${params.sessionId} durationMs=${Date.now() - promptStartedAt}`,
|
||||
|
||||
// Check if last message is a user message to prevent consecutive user turns
|
||||
const lastMsg = activeSession.messages[activeSession.messages.length - 1];
|
||||
const lastMsgRole = lastMsg && typeof lastMsg === "object" ? (lastMsg as { role?: unknown }).role : undefined;
|
||||
|
||||
if (lastMsgRole === "user") {
|
||||
// Last message was a user message. Adding another user message would create
|
||||
// consecutive user turns, violating Anthropic's role ordering requirement.
|
||||
// This can happen when:
|
||||
// 1. A previous heartbeat didn't get a response
|
||||
// 2. A user message errored before getting an assistant response
|
||||
// Skip this prompt to prevent "400 Incorrect role information" error.
|
||||
log.warn(
|
||||
`Skipping prompt because last message is a user message (would create consecutive user turns). ` +
|
||||
`runId=${params.runId} sessionId=${params.sessionId}`
|
||||
);
|
||||
promptError = new Error("Incorrect role information: consecutive user messages would violate role ordering");
|
||||
} else {
|
||||
try {
|
||||
await activeSession.prompt(params.prompt, { images: params.images });
|
||||
} catch (err) {
|
||||
promptError = err;
|
||||
} finally {
|
||||
log.debug(
|
||||
`embedded run prompt end: runId=${params.runId} sessionId=${params.sessionId} durationMs=${Date.now() - promptStartedAt}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -63,6 +63,8 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
const normalizedRawErrorText = rawErrorMessage
|
||||
? normalizeTextForComparison(rawErrorMessage)
|
||||
: null;
|
||||
const normalizedErrorText = errorText ? normalizeTextForComparison(errorText) : null;
|
||||
const genericErrorText = "The AI service returned an error. Please try again.";
|
||||
if (errorText) replyItems.push({ text: errorText, isError: true });
|
||||
|
||||
const inlineToolResults =
|
||||
@@ -102,6 +104,11 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
if (!lastAssistantErrored) return false;
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return false;
|
||||
if (errorText) {
|
||||
const normalized = normalizeTextForComparison(trimmed);
|
||||
if (normalized && normalizedErrorText && normalized === normalizedErrorText) return true;
|
||||
if (trimmed === genericErrorText) return true;
|
||||
}
|
||||
if (rawErrorMessage && trimmed === rawErrorMessage) return true;
|
||||
if (normalizedRawErrorText) {
|
||||
const normalized = normalizeTextForComparison(trimmed);
|
||||
|
||||
Reference in New Issue
Block a user