Improve X assistant pairing required guidance
This commit is contained in:
parent
be30303bc8
commit
00023b808b
@ -89,7 +89,7 @@ function formatGatewayError(error: OpenClawGatewayError | null, client: OpenClaw
|
||||
const requestId = stringValue(details.requestId)
|
||||
const reason = stringValue(details.reason)
|
||||
return [
|
||||
'需要先在 OpenClaw 网关审批该设备配对请求。',
|
||||
'等待管理员审批当前设备后,X 助手才能继续连接。',
|
||||
requestId ? `requestId: ${requestId}` : '',
|
||||
client.deviceId ? `deviceId: ${client.deviceId}` : '',
|
||||
reason ? `reason: ${reason}` : '',
|
||||
@ -382,6 +382,8 @@ async function handleSend(body: SendBody, request: NextRequest): Promise<Respons
|
||||
type: 'error',
|
||||
message: gatewayError?.message ?? 'Failed to send message to OpenClaw gateway.',
|
||||
...(gatewayError?.code ? { code: gatewayError.code } : {}),
|
||||
...(gatewayError?.details ? { details: gatewayError.details } : {}),
|
||||
...(client?.deviceId ? { deviceId: client.deviceId } : {}),
|
||||
})
|
||||
controller.close()
|
||||
if (client) {
|
||||
|
||||
@ -63,6 +63,13 @@ type ComposerAttachment = GatewayChatAttachmentPayload & {
|
||||
|
||||
type ConnectionState = "idle" | "connecting" | "ready" | "error";
|
||||
|
||||
type AssistantApiErrorPayload = {
|
||||
error?: string;
|
||||
code?: string;
|
||||
details?: Record<string, unknown> | null;
|
||||
deviceId?: string;
|
||||
};
|
||||
|
||||
export type OpenClawAssistantViewState = {
|
||||
connectionState: ConnectionState;
|
||||
healthBadge: string;
|
||||
@ -84,6 +91,47 @@ function pickCopy(isChinese: boolean, zh: string, en: string): string {
|
||||
return isChinese ? zh : en;
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: {};
|
||||
}
|
||||
|
||||
function stringValue(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
||||
}
|
||||
|
||||
function formatAssistantApiError(params: {
|
||||
payload: AssistantApiErrorPayload;
|
||||
isChinese: boolean;
|
||||
fallback: string;
|
||||
}): string {
|
||||
const message = params.payload.error?.trim();
|
||||
if (params.payload.code !== "PAIRING_REQUIRED") {
|
||||
return message || params.fallback;
|
||||
}
|
||||
|
||||
const details = asRecord(params.payload.details);
|
||||
const requestId = stringValue(details.requestId);
|
||||
const deviceId =
|
||||
params.payload.deviceId?.trim() || stringValue(details.deviceId);
|
||||
const reason = stringValue(details.reason);
|
||||
|
||||
return [
|
||||
pickCopy(
|
||||
params.isChinese,
|
||||
"等待管理员审批当前设备后,X 助手才能继续连接。",
|
||||
"Waiting for an administrator to approve this device before X Assistant can continue.",
|
||||
),
|
||||
deviceId ? `deviceId: ${deviceId}` : "",
|
||||
requestId ? `requestId: ${requestId}` : "",
|
||||
reason ? `reason: ${reason}` : "",
|
||||
message && message !== params.fallback ? message : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
function renderMarkdown(value: string): string {
|
||||
return DOMPurify.sanitize(marked.parse(value) as string);
|
||||
}
|
||||
@ -517,10 +565,16 @@ export function OpenClawAssistantPane({
|
||||
|
||||
const payload = (await response.json()) as
|
||||
| OpenClawBootstrapResponse
|
||||
| { error?: string };
|
||||
| AssistantApiErrorPayload;
|
||||
|
||||
if (!response.ok || "error" in payload) {
|
||||
throw new Error((payload as { error?: string }).error || copy.bootstrapFailed);
|
||||
throw new Error(
|
||||
formatAssistantApiError({
|
||||
payload: payload as AssistantApiErrorPayload,
|
||||
isChinese,
|
||||
fallback: copy.bootstrapFailed,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const data = payload as OpenClawBootstrapResponse;
|
||||
@ -546,6 +600,7 @@ export function OpenClawAssistantPane({
|
||||
copy.bootstrapFailed,
|
||||
copy.connectFailed,
|
||||
copy.serverMissing,
|
||||
isChinese,
|
||||
openclawToken,
|
||||
openclawOrigin,
|
||||
openclawUrl,
|
||||
@ -672,8 +727,14 @@ export function OpenClawAssistantPane({
|
||||
if (!response.ok || !response.body) {
|
||||
const payload = await response
|
||||
.json()
|
||||
.catch(() => ({ error: copy.sendFailed }));
|
||||
throw new Error(payload.error || copy.sendFailed);
|
||||
.catch(() => ({ error: copy.sendFailed } as AssistantApiErrorPayload));
|
||||
throw new Error(
|
||||
formatAssistantApiError({
|
||||
payload: payload as AssistantApiErrorPayload,
|
||||
isChinese,
|
||||
fallback: copy.sendFailed,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const reader = response.body.getReader();
|
||||
@ -715,7 +776,18 @@ export function OpenClawAssistantPane({
|
||||
}
|
||||
|
||||
if (event.type === "error") {
|
||||
setErrorMessage(event.message);
|
||||
setErrorMessage(
|
||||
formatAssistantApiError({
|
||||
payload: {
|
||||
error: event.message,
|
||||
code: event.code,
|
||||
details: event.details ?? null,
|
||||
deviceId: event.deviceId,
|
||||
},
|
||||
isChinese,
|
||||
fallback: copy.sendFailed,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1151,7 +1223,7 @@ export function OpenClawAssistantPane({
|
||||
) : null}
|
||||
|
||||
{errorMessage ? (
|
||||
<div className="mt-2.5 rounded-[var(--radius-lg)] border border-[color:var(--color-danger-border)] bg-[var(--color-danger-muted)]/40 px-3 py-2 text-sm text-[var(--color-danger-foreground)]">
|
||||
<div className="mt-2.5 whitespace-pre-wrap rounded-[var(--radius-lg)] border border-[color:var(--color-danger-border)] bg-[var(--color-danger-muted)]/40 px-3 py-2 text-sm text-[var(--color-danger-foreground)]">
|
||||
{errorMessage}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@ -75,6 +75,8 @@ export type OpenClawStreamEvent =
|
||||
type: 'error'
|
||||
message: string
|
||||
code?: string
|
||||
details?: Record<string, unknown> | null
|
||||
deviceId?: string
|
||||
}
|
||||
|
||||
export type IntegrationDefaults = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user