refactor: align status with plugin memory slot
This commit is contained in:
@@ -65,6 +65,7 @@ export async function statusCommand(
|
||||
channels,
|
||||
summary,
|
||||
memory,
|
||||
memoryPlugin,
|
||||
} = scan;
|
||||
|
||||
const securityAudit = await withProgress(
|
||||
@@ -116,6 +117,7 @@ export async function statusCommand(
|
||||
os: osSummary,
|
||||
update,
|
||||
memory,
|
||||
memoryPlugin,
|
||||
gateway: {
|
||||
mode: gatewayMode,
|
||||
url: gatewayConnection.url,
|
||||
@@ -235,11 +237,19 @@ export async function statusCommand(
|
||||
: (summary.sessions.paths[0] ?? "unknown");
|
||||
|
||||
const memoryValue = (() => {
|
||||
if (!memory) return muted("disabled");
|
||||
if (!memoryPlugin.enabled) {
|
||||
const suffix = memoryPlugin.reason ? ` (${memoryPlugin.reason})` : "";
|
||||
return muted(`disabled${suffix}`);
|
||||
}
|
||||
if (!memory) {
|
||||
const slot = memoryPlugin.slot ? `plugin ${memoryPlugin.slot}` : "plugin";
|
||||
return muted(`enabled (${slot}) · unavailable`);
|
||||
}
|
||||
const parts: string[] = [];
|
||||
const dirtySuffix = memory.dirty ? ` · ${warn("dirty")}` : "";
|
||||
parts.push(`${memory.files} files · ${memory.chunks} chunks${dirtySuffix}`);
|
||||
if (memory.sources?.length) parts.push(`sources ${memory.sources.join(", ")}`);
|
||||
if (memoryPlugin.slot) parts.push(`plugin ${memoryPlugin.slot}`);
|
||||
const vector = memory.vector;
|
||||
parts.push(
|
||||
vector?.enabled === false
|
||||
|
||||
@@ -19,6 +19,22 @@ type MemoryStatusSnapshot = ReturnType<(typeof MemoryIndexManager)["prototype"][
|
||||
agentId: string;
|
||||
};
|
||||
|
||||
type MemoryPluginStatus = {
|
||||
enabled: boolean;
|
||||
slot: string | null;
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
function resolveMemoryPluginStatus(cfg: ReturnType<typeof loadConfig>): MemoryPluginStatus {
|
||||
const pluginsEnabled = cfg.plugins?.enabled !== false;
|
||||
if (!pluginsEnabled) return { enabled: false, slot: null, reason: "plugins disabled" };
|
||||
const raw = typeof cfg.plugins?.slots?.memory === "string" ? cfg.plugins.slots.memory.trim() : "";
|
||||
if (raw && raw.toLowerCase() === "none") {
|
||||
return { enabled: false, slot: null, reason: 'plugins.slots.memory="none"' };
|
||||
}
|
||||
return { enabled: true, slot: raw || "memory-core" };
|
||||
}
|
||||
|
||||
export type StatusScanResult = {
|
||||
cfg: ReturnType<typeof loadConfig>;
|
||||
osSummary: ReturnType<typeof resolveOsSummary>;
|
||||
@@ -37,6 +53,7 @@ export type StatusScanResult = {
|
||||
channels: Awaited<ReturnType<typeof buildChannelsTable>>;
|
||||
summary: Awaited<ReturnType<typeof getStatusSummary>>;
|
||||
memory: MemoryStatusSnapshot | null;
|
||||
memoryPlugin: MemoryPluginStatus;
|
||||
};
|
||||
|
||||
export async function scanStatus(
|
||||
@@ -129,7 +146,10 @@ export async function scanStatus(
|
||||
progress.tick();
|
||||
|
||||
progress.setLabel("Checking memory…");
|
||||
const memoryPlugin = resolveMemoryPluginStatus(cfg);
|
||||
const memory = await (async (): Promise<MemoryStatusSnapshot | null> => {
|
||||
if (!memoryPlugin.enabled) return null;
|
||||
if (memoryPlugin.slot !== "memory-core") return null;
|
||||
const agentId = agentStatus.defaultId ?? "main";
|
||||
const manager = await MemoryIndexManager.get({ cfg, agentId }).catch(() => null);
|
||||
if (!manager) return null;
|
||||
@@ -167,6 +187,7 @@ export async function scanStatus(
|
||||
channels,
|
||||
summary,
|
||||
memory,
|
||||
memoryPlugin,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
@@ -261,6 +261,8 @@ describe("statusCommand", () => {
|
||||
const payload = JSON.parse((runtime.log as vi.Mock).mock.calls[0][0]);
|
||||
expect(payload.linkChannel.linked).toBe(true);
|
||||
expect(payload.memory.agentId).toBe("main");
|
||||
expect(payload.memoryPlugin.enabled).toBe(true);
|
||||
expect(payload.memoryPlugin.slot).toBe("memory-core");
|
||||
expect(payload.memory.vector.available).toBe(true);
|
||||
expect(payload.sessions.count).toBe(1);
|
||||
expect(payload.sessions.paths).toContain("/tmp/sessions.json");
|
||||
|
||||
@@ -7,17 +7,19 @@ import {
|
||||
resolveInboundDebounceMs,
|
||||
} from "../../auto-reply/inbound-debounce.js";
|
||||
import { buildMentionRegexes, matchesMentionPatterns } from "../../auto-reply/reply/mentions.js";
|
||||
import { dispatchReplyWithBufferedBlockDispatcher } from "../../auto-reply/reply/provider-dispatcher.js";
|
||||
import type { ReplyPayload } from "../../auto-reply/types.js";
|
||||
import type { ReplyDispatchKind, ReplyDispatcherWithTypingOptions } from "../../auto-reply/reply/reply-dispatcher.js";
|
||||
import { dispatchReplyWithBufferedBlockDispatcher as dispatchReplyWithBufferedBlockDispatcherImpl } from "../../auto-reply/reply/provider-dispatcher.js";
|
||||
import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js";
|
||||
import { resolveEffectiveMessagesConfig, resolveHumanDelayConfig } from "../../agents/identity.js";
|
||||
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
|
||||
import {
|
||||
resolveChannelGroupPolicy,
|
||||
resolveChannelGroupRequireMention,
|
||||
} from "../../config/group-policy.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { GroupPolicyChannel } from "../../config/group-policy.js";
|
||||
import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "../../config/group-policy.js";
|
||||
import { resolveStateDir } from "../../config/paths.js";
|
||||
import { shouldLogVerbose } from "../../globals.js";
|
||||
import { getChildLogger } from "../../logging.js";
|
||||
import { normalizeLogLevel } from "../../logging/levels.js";
|
||||
import { fetchRemoteMedia } from "../../media/fetch.js";
|
||||
import { saveMediaBuffer } from "../../media/store.js";
|
||||
import { buildPairingReply } from "../../pairing/pairing-messages.js";
|
||||
@@ -26,6 +28,7 @@ import {
|
||||
upsertChannelPairingRequest,
|
||||
} from "../../pairing/pairing-store.js";
|
||||
import { resolveAgentRoute } from "../../routing/resolve-route.js";
|
||||
import type { FinalizedMsgContext } from "../../auto-reply/templating.js";
|
||||
|
||||
import type { PluginRuntime } from "./types.js";
|
||||
|
||||
@@ -54,13 +57,41 @@ export function createPluginRuntime(): PluginRuntime {
|
||||
hasControlCommand,
|
||||
},
|
||||
reply: {
|
||||
dispatchReplyWithBufferedBlockDispatcher,
|
||||
createReplyDispatcherWithTyping,
|
||||
dispatchReplyWithBufferedBlockDispatcher: async (params) => {
|
||||
const dispatcherOptions = params.dispatcherOptions;
|
||||
const deliver = async (payload: ReplyPayload, _info: { kind: ReplyDispatchKind }) => {
|
||||
await dispatcherOptions.deliver(payload);
|
||||
};
|
||||
const onError = dispatcherOptions.onError
|
||||
? (err: unknown, info: { kind: ReplyDispatchKind }) => {
|
||||
dispatcherOptions.onError?.(err, { kind: info.kind });
|
||||
}
|
||||
: undefined;
|
||||
|
||||
await dispatchReplyWithBufferedBlockDispatcherImpl({
|
||||
ctx: params.ctx as FinalizedMsgContext,
|
||||
cfg: params.cfg as ClawdbotConfig,
|
||||
dispatcherOptions: {
|
||||
deliver,
|
||||
onError,
|
||||
} satisfies ReplyDispatcherWithTypingOptions,
|
||||
});
|
||||
},
|
||||
createReplyDispatcherWithTyping: (...args) =>
|
||||
createReplyDispatcherWithTyping(args[0] as ReplyDispatcherWithTypingOptions),
|
||||
resolveEffectiveMessagesConfig,
|
||||
resolveHumanDelayConfig,
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute,
|
||||
resolveAgentRoute: (params) => {
|
||||
const resolved = resolveAgentRoute({
|
||||
cfg: params.cfg as ClawdbotConfig,
|
||||
channel: params.channel,
|
||||
accountId: params.accountId,
|
||||
peer: params.peer,
|
||||
});
|
||||
return { sessionKey: resolved.sessionKey, accountId: resolved.accountId };
|
||||
},
|
||||
},
|
||||
pairing: {
|
||||
buildPairingReply,
|
||||
@@ -69,19 +100,61 @@ export function createPluginRuntime(): PluginRuntime {
|
||||
},
|
||||
media: {
|
||||
fetchRemoteMedia,
|
||||
saveMediaBuffer,
|
||||
saveMediaBuffer: async (buffer, contentType, direction, maxBytes) => {
|
||||
const saved = await saveMediaBuffer(
|
||||
Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer),
|
||||
contentType,
|
||||
direction,
|
||||
maxBytes,
|
||||
);
|
||||
return { path: saved.path, contentType: saved.contentType };
|
||||
},
|
||||
},
|
||||
mentions: {
|
||||
buildMentionRegexes,
|
||||
matchesMentionPatterns,
|
||||
},
|
||||
groups: {
|
||||
resolveGroupPolicy: resolveChannelGroupPolicy,
|
||||
resolveRequireMention: resolveChannelGroupRequireMention,
|
||||
resolveGroupPolicy: (cfg, channel, accountId, groupId) =>
|
||||
resolveChannelGroupPolicy({
|
||||
cfg,
|
||||
channel: channel as GroupPolicyChannel,
|
||||
accountId,
|
||||
groupId,
|
||||
}),
|
||||
resolveRequireMention: (cfg, channel, accountId, groupId, override) =>
|
||||
resolveChannelGroupRequireMention({
|
||||
cfg,
|
||||
channel: channel as GroupPolicyChannel,
|
||||
accountId,
|
||||
groupId,
|
||||
requireMentionOverride: override,
|
||||
}),
|
||||
},
|
||||
debounce: {
|
||||
createInboundDebouncer,
|
||||
resolveInboundDebounceMs,
|
||||
createInboundDebouncer: (opts) => {
|
||||
const keys = new Set<string>();
|
||||
const debouncer = createInboundDebouncer({
|
||||
debounceMs: opts.debounceMs,
|
||||
buildKey: opts.buildKey,
|
||||
shouldDebounce: opts.shouldDebounce ?? (() => true),
|
||||
onFlush: opts.onFlush,
|
||||
onError: opts.onError ? (err: unknown) => opts.onError?.(err) : undefined,
|
||||
});
|
||||
return {
|
||||
push: (value) => {
|
||||
const key = opts.buildKey(value);
|
||||
if (key) keys.add(key);
|
||||
void debouncer.enqueue(value);
|
||||
},
|
||||
flush: async () => {
|
||||
const flushKeys = Array.from(keys);
|
||||
keys.clear();
|
||||
for (const key of flushKeys) await debouncer.flushKey(key);
|
||||
},
|
||||
};
|
||||
},
|
||||
resolveInboundDebounceMs: (cfg, channel) => resolveInboundDebounceMs({ cfg, channel }),
|
||||
},
|
||||
commands: {
|
||||
resolveCommandAuthorizedFromAuthorizers,
|
||||
@@ -90,7 +163,9 @@ export function createPluginRuntime(): PluginRuntime {
|
||||
logging: {
|
||||
shouldLogVerbose,
|
||||
getChildLogger: (bindings, opts) => {
|
||||
const logger = getChildLogger(bindings, opts);
|
||||
const logger = getChildLogger(bindings, {
|
||||
level: opts?.level ? normalizeLogLevel(opts.level) : undefined,
|
||||
});
|
||||
return {
|
||||
debug: (message) => logger.debug?.(message),
|
||||
info: (message) => logger.info(message),
|
||||
@@ -100,7 +175,7 @@ export function createPluginRuntime(): PluginRuntime {
|
||||
},
|
||||
},
|
||||
state: {
|
||||
resolveStateDir,
|
||||
resolveStateDir: () => resolveStateDir(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user