fix: improve remote bin probe logging

This commit is contained in:
Peter Steinberger
2026-01-18 16:09:43 +00:00
parent 835162fb62
commit 810394f43b
3 changed files with 49 additions and 2 deletions

View File

@@ -84,6 +84,7 @@ Docs: https://docs.clawd.bot
- macOS: avoid touching launchd in Remote over SSH so quitting the app no longer disables the remote gateway. (#1105) - macOS: avoid touching launchd in Remote over SSH so quitting the app no longer disables the remote gateway. (#1105)
- Memory: index atomically so failed reindex preserves the previous memory database. (#1151) - Memory: index atomically so failed reindex preserves the previous memory database. (#1151)
- Memory: avoid sqlite-vec unique constraint failures when reindexing duplicate chunk ids. (#1151) - Memory: avoid sqlite-vec unique constraint failures when reindexing duplicate chunk ids. (#1151)
- Skills: improve remote bin probe logging with node labels + connectivity hints.
- Exec approvals: enforce allowlist when ask is off; prefer raw command for node approvals/events. - Exec approvals: enforce allowlist when ask is off; prefer raw command for node approvals/events.
- Tools: return a companion-app-required message when node exec is requested with no paired node. - Tools: return a companion-app-required message when node exec is requested with no paired node.
- Streaming: emit assistant deltas for OpenAI-compatible SSE chunks. (#1147) — thanks @alauppe. - Streaming: emit assistant deltas for OpenAI-compatible SSE chunks. (#1147) — thanks @alauppe.

View File

@@ -148,6 +148,7 @@ export async function startGatewayNodeBridge(params: {
platform: node.platform, platform: node.platform,
deviceFamily: node.deviceFamily, deviceFamily: node.deviceFamily,
commands: node.commands, commands: node.commands,
remoteIp: node.remoteIp,
}); });
bumpSkillsSnapshotVersion({ reason: "remote-node" }); bumpSkillsSnapshotVersion({ reason: "remote-node" });
await refreshRemoteNodeBins({ await refreshRemoteNodeBins({

View File

@@ -14,12 +14,53 @@ type RemoteNodeRecord = {
deviceFamily?: string; deviceFamily?: string;
commands?: string[]; commands?: string[];
bins: Set<string>; bins: Set<string>;
remoteIp?: string;
}; };
const log = createSubsystemLogger("gateway/skills-remote"); const log = createSubsystemLogger("gateway/skills-remote");
const remoteNodes = new Map<string, RemoteNodeRecord>(); const remoteNodes = new Map<string, RemoteNodeRecord>();
let remoteBridge: NodeBridgeServer | null = null; let remoteBridge: NodeBridgeServer | null = null;
function describeNode(nodeId: string): string {
const record = remoteNodes.get(nodeId);
const name = record?.displayName?.trim();
const base = name && name !== nodeId ? `${name} (${nodeId})` : nodeId;
const ip = record?.remoteIp?.trim();
return ip ? `${base} @ ${ip}` : base;
}
function extractErrorMessage(err: unknown): string | undefined {
if (!err) return undefined;
if (typeof err === "string") return err;
if (err instanceof Error) return err.message;
if (typeof err === "object" && "message" in err && typeof err.message === "string") {
return err.message;
}
return String(err);
}
function logRemoteBinProbeFailure(nodeId: string, err: unknown) {
const message = extractErrorMessage(err);
const label = describeNode(nodeId);
if (message?.includes("UNAVAILABLE: node not connected")) {
log.info(
`remote bin probe skipped: node not connected (${label}); check nodes list/status for ${label}`,
);
return;
}
if (message?.includes("UNAVAILABLE: invoke timeout")) {
log.warn(`remote bin probe timed out (${label}); check node connectivity for ${label}`);
return;
}
if (message?.includes("bridge connection closed")) {
log.warn(
`remote bin probe aborted: bridge connection closed (${label}); check nodes list/status for ${label}`,
);
return;
}
log.warn(`remote bin probe error (${label}): ${message ?? "unknown"}`);
}
function isMacPlatform(platform?: string, deviceFamily?: string): boolean { function isMacPlatform(platform?: string, deviceFamily?: string): boolean {
const platformNorm = String(platform ?? "") const platformNorm = String(platform ?? "")
.trim() .trim()
@@ -47,6 +88,7 @@ function upsertNode(record: {
platform?: string; platform?: string;
deviceFamily?: string; deviceFamily?: string;
commands?: string[]; commands?: string[];
remoteIp?: string;
bins?: string[]; bins?: string[];
}) { }) {
const existing = remoteNodes.get(record.nodeId); const existing = remoteNodes.get(record.nodeId);
@@ -57,6 +99,7 @@ function upsertNode(record: {
platform: record.platform ?? existing?.platform, platform: record.platform ?? existing?.platform,
deviceFamily: record.deviceFamily ?? existing?.deviceFamily, deviceFamily: record.deviceFamily ?? existing?.deviceFamily,
commands: record.commands ?? existing?.commands, commands: record.commands ?? existing?.commands,
remoteIp: record.remoteIp ?? existing?.remoteIp,
bins, bins,
}); });
} }
@@ -76,6 +119,7 @@ export async function primeRemoteSkillsCache() {
platform: node.platform, platform: node.platform,
deviceFamily: node.deviceFamily, deviceFamily: node.deviceFamily,
commands: node.commands, commands: node.commands,
remoteIp: node.remoteIp,
bins: node.bins, bins: node.bins,
}); });
if (isMacPlatform(node.platform, node.deviceFamily) && supportsSystemRun(node.commands)) { if (isMacPlatform(node.platform, node.deviceFamily) && supportsSystemRun(node.commands)) {
@@ -96,6 +140,7 @@ export function recordRemoteNodeInfo(node: {
platform?: string; platform?: string;
deviceFamily?: string; deviceFamily?: string;
commands?: string[]; commands?: string[];
remoteIp?: string;
}) { }) {
upsertNode(node); upsertNode(node);
} }
@@ -203,7 +248,7 @@ export async function refreshRemoteNodeBins(params: {
}, },
); );
if (!res.ok) { if (!res.ok) {
log.warn(`remote bin probe failed (${params.nodeId}): ${res.error?.message ?? "unknown"}`); logRemoteBinProbeFailure(params.nodeId, res.error?.message ?? "unknown");
return; return;
} }
const bins = parseBinProbePayload(res.payloadJSON); const bins = parseBinProbePayload(res.payloadJSON);
@@ -211,7 +256,7 @@ export async function refreshRemoteNodeBins(params: {
await updatePairedNodeMetadata(params.nodeId, { bins }); await updatePairedNodeMetadata(params.nodeId, { bins });
bumpSkillsSnapshotVersion({ reason: "remote-node" }); bumpSkillsSnapshotVersion({ reason: "remote-node" });
} catch (err) { } catch (err) {
log.warn(`remote bin probe error (${params.nodeId}): ${String(err)}`); logRemoteBinProbeFailure(params.nodeId, err);
} }
} }