Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

318 lines
11 KiB
TypeScript

import type {
PendingSubmitIntentRecord,
SessionGoalControlSettlement
} from "@tutti-os/agent-activity-core";
import { translate } from "../../../i18n/index";
import type { AppErrorCode } from "../../../shared/contracts/dto";
import { getAppErrorCode } from "../../../shared/errors/appError";
import { AGENT_PROVIDER_LABEL } from "../../../contexts/settings/domain/agentSettings";
export const AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR =
"agent.provider_session_not_found";
export const AGENT_RESUME_SESSION_NOT_LOCAL_ERROR =
"agent.resume_session_not_local";
export const AGENT_SETTINGS_REQUIRE_NEW_SESSION_ERROR =
"agent.settings_require_new_session";
export const AGENT_CONFIG_DEPENDENCY_UNAVAILABLE_REASON =
"agent.config_dependency_unavailable";
export const AGENT_PROCESS_CLEANUP_PENDING_REASON =
"agent.process_cleanup_pending";
export const AGENT_SESSION_TITLE_TOO_LONG_REASON =
"workspace_agent_session_title_too_long";
export const AGENT_SESSION_NOT_FOUND_ERROR = "session.not_found";
export const AGENT_PROVIDER_SESSION_NOT_FOUND_FALLBACK_MESSAGE =
"The previous agent session can no longer be restored.";
export const AGENT_RESUME_SESSION_NOT_LOCAL_FALLBACK_MESSAGE =
"The previous agent session is not available on this machine.";
export const AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT = 4000;
export function goalControlSettlementError(
settlement: SessionGoalControlSettlement
): Error {
const error = new Error(settlement.errorMessage ?? "") as Error & {
code?: string;
reason?: string;
};
if (settlement.errorCode) error.code = settlement.errorCode;
if (settlement.errorReason) error.reason = settlement.errorReason;
return error;
}
export function agentGUISubmitSettlementError(
submit: Pick<
PendingSubmitIntentRecord,
"errorCode" | "errorMessage" | "errorReason"
>
): Error {
return Object.assign(
new Error(
submit.errorMessage?.trim() || translate("agentHost.agentGui.sendFailed")
),
{
...(submit.errorCode ? { code: submit.errorCode } : {}),
...(submit.errorReason ? { reason: submit.errorReason } : {})
}
);
}
export function normalizeAgentGUIDiagnosticError(
error: unknown
): Record<string, unknown> {
const record =
error && typeof error === "object"
? (error as Record<string, unknown>)
: null;
const appErrorCode = getAgentGUIErrorCode(error);
const configDependency = getAgentGUIConfigDependencyErrorDetails(error);
const explicitCode = typeof record?.code === "string" ? record.code : null;
const hasStructuredCode = appErrorCode !== null || explicitCode !== null;
const nativeRuntimeError =
error instanceof Error && isNativeRuntimeError(error);
const base: Record<string, unknown> = {
...(error instanceof Error ? { name: error.name } : {}),
...(explicitCode ? { code: explicitCode } : {}),
...(typeof record?.statusCode === "number"
? { statusCode: record.statusCode }
: {}),
...(typeof record?.correlationId === "string"
? { correlationId: record.correlationId }
: {}),
...(typeof record?.reason === "string" ? { reason: record.reason } : {}),
...(typeof record?.retryable === "boolean"
? { retryable: record.retryable }
: {}),
...(configDependency
? {
configKey: configDependency.configKey,
dependencyPath: configDependency.dependencyPath,
dependencyProvider: configDependency.provider,
failureKind: configDependency.failureKind
}
: {})
};
if (nativeRuntimeError) {
return {
...base,
message: error.message,
...(error.stack ? { stack: limitDiagnosticText(error.stack) } : {})
};
}
if (record) {
return {
...base,
...(typeof record.name === "string" && !("name" in base)
? { name: record.name }
: {}),
...(typeof record.message === "string"
? { messageLength: record.message.length }
: {}),
...(typeof record.debugMessage === "string"
? { debugMessageLength: record.debugMessage.length }
: {})
};
}
const rawMessage = getAgentGUIRawErrorMessage(error);
return {
...(hasStructuredCode ? {} : { messageLength: rawMessage?.length ?? 0 }),
type: typeof error
};
}
export function isNativeRuntimeError(error: Error): boolean {
return (
error instanceof RangeError ||
error instanceof ReferenceError ||
error instanceof SyntaxError ||
error instanceof TypeError ||
error instanceof URIError
);
}
export function limitDiagnosticText(value: string): string {
return value.length <= AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT
? value
: `${value.slice(0, AGENT_GUI_CAUGHT_ERROR_STACK_LIMIT)}...`;
}
export function getAgentGUIErrorCode(error: unknown): AppErrorCode | null {
return (
getAppErrorCode(error) ??
inferAgentGUIErrorCodeFromReason(getAgentGUIErrorReason(error)) ??
inferAgentGUIErrorCodeFromMessage(getAgentGUIRawErrorMessage(error))
);
}
export function getAgentGUIErrorReason(error: unknown): string | null {
if (!error || typeof error !== "object") return null;
const reason = (error as { reason?: unknown }).reason;
return typeof reason === "string" && reason.trim() ? reason.trim() : null;
}
export function inferAgentGUIErrorCodeFromReason(
reason: string | null
): AppErrorCode | null {
return reason === AGENT_SETTINGS_REQUIRE_NEW_SESSION_ERROR
? (AGENT_SETTINGS_REQUIRE_NEW_SESSION_ERROR as AppErrorCode)
: null;
}
export function inferAgentGUIErrorCodeFromMessage(
message: string | null
): AppErrorCode | null {
switch (message?.trim()) {
case AGENT_PROVIDER_SESSION_NOT_FOUND_FALLBACK_MESSAGE:
return AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR as AppErrorCode;
case AGENT_RESUME_SESSION_NOT_LOCAL_FALLBACK_MESSAGE:
return AGENT_RESUME_SESSION_NOT_LOCAL_ERROR as AppErrorCode;
default:
return null;
}
}
export function isProviderSessionNotFoundErrorCode(
code: AppErrorCode | null | undefined
): boolean {
return code === AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR;
}
export function isResumeSessionNotLocalErrorCode(
code: AppErrorCode | null | undefined
): boolean {
return code === AGENT_RESUME_SESSION_NOT_LOCAL_ERROR;
}
export function isNonRetryableResumeErrorCode(
code: AppErrorCode | null | undefined
): boolean {
return (
isProviderSessionNotFoundErrorCode(code) ||
isResumeSessionNotLocalErrorCode(code)
);
}
export function isSessionNotFoundErrorCode(
code: AppErrorCode | null | undefined
): boolean {
return code === AGENT_SESSION_NOT_FOUND_ERROR;
}
export function isSettingsRequireNewSessionErrorCode(
code: AppErrorCode | null | undefined
): boolean {
return code === AGENT_SETTINGS_REQUIRE_NEW_SESSION_ERROR;
}
export function buildProviderSessionNotFoundActivationError(
message?: string | null
): {
code: AppErrorCode;
message: string;
debugMessage?: string;
} {
const normalizedMessage = message?.trim() || null;
return {
code: AGENT_PROVIDER_SESSION_NOT_FOUND_ERROR,
message: translate("messages.agentProviderSessionNotFound"),
...(normalizedMessage ? { debugMessage: normalizedMessage } : {})
};
}
export function buildResumeSessionNotLocalActivationError(
message?: string | null
): {
code: AppErrorCode;
message: string;
debugMessage?: string;
} {
const normalizedMessage = message?.trim() || null;
return {
code: AGENT_RESUME_SESSION_NOT_LOCAL_ERROR,
message: translate("messages.agentResumeSessionNotLocal"),
...(normalizedMessage ? { debugMessage: normalizedMessage } : {})
};
}
export function getAgentGUIErrorMessage(error: unknown): string {
const configDependency = getAgentGUIConfigDependencyErrorDetails(error);
if (configDependency) {
const provider =
AGENT_PROVIDER_LABEL[
configDependency.provider as keyof typeof AGENT_PROVIDER_LABEL
] ||
configDependency.provider ||
translate("sidebar.fallbackAgentLabel");
return translate("messages.agentConfigDependencyUnavailable", {
provider
});
}
if (getAgentGUIErrorReason(error) === AGENT_PROCESS_CLEANUP_PENDING_REASON)
return translate("messages.agentProcessCleanupPending");
const code = getAgentGUIErrorCode(error);
if (isProviderSessionNotFoundErrorCode(code))
return translate("messages.agentProviderSessionNotFound");
if (isResumeSessionNotLocalErrorCode(code))
return translate("messages.agentResumeSessionNotLocal");
if (isSettingsRequireNewSessionErrorCode(code))
return translate("messages.agentSettingsRequireNewSession");
if (getAgentGUIErrorReason(error) === AGENT_SESSION_TITLE_TOO_LONG_REASON) {
const maxCharacters = getAgentGUIErrorNumberParam(error, "maxCharacters");
return maxCharacters === null
? translate("messages.agentSessionTitleTooLongWithoutLimit")
: translate("messages.agentSessionTitleTooLong", { maxCharacters });
}
if (error && typeof error === "object") {
const debugMessage = (error as { debugMessage?: unknown }).debugMessage;
if (typeof debugMessage === "string" && debugMessage.trim())
return debugMessage.trim();
}
return error instanceof Error ? error.message : String(error);
}
function getAgentGUIConfigDependencyErrorDetails(error: unknown): {
provider: string;
configKey: string;
dependencyPath: string;
failureKind: string;
} | null {
if (!error || typeof error !== "object") return null;
const record = error as Record<string, unknown>;
if (record.reason !== AGENT_CONFIG_DEPENDENCY_UNAVAILABLE_REASON) return null;
const params =
record.params && typeof record.params === "object"
? (record.params as Record<string, unknown>)
: {};
return {
provider: normalizedString(params.provider),
configKey: normalizedString(params.configKey),
dependencyPath: normalizedString(params.dependencyPath),
failureKind: normalizedString(params.failureKind)
};
}
function normalizedString(value: unknown): string {
return typeof value === "string" ? value.trim() : "";
}
function getAgentGUIErrorNumberParam(
error: unknown,
key: string
): number | null {
if (!error || typeof error !== "object") return null;
const params = (error as { params?: unknown }).params;
if (!params || typeof params !== "object") return null;
const value = (params as Record<string, unknown>)[key];
return typeof value === "number" && Number.isFinite(value) ? value : null;
}
export function getAgentGUIRawErrorMessage(error: unknown): string | null {
if (error && typeof error === "object") {
const debugMessage = (error as { debugMessage?: unknown }).debugMessage;
if (typeof debugMessage === "string" && debugMessage.trim())
return debugMessage.trim();
}
if (error instanceof Error && error.message.trim())
return error.message.trim();
if (typeof error === "string" && error.trim()) return error.trim();
return null;
}