fix: improve remote bin probe logging
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user