Fix build errors
This commit is contained in:
parent
f3f1640c7b
commit
62e80d030c
@ -109,6 +109,13 @@ out to QMD for retrieval. Key points:
|
|||||||
a release) and make sure the `qmd` binary is on the gateway’s `PATH`.
|
a release) and make sure the `qmd` binary is on the gateway’s `PATH`.
|
||||||
- QMD needs an SQLite build that allows extensions (`brew install sqlite` on
|
- QMD needs an SQLite build that allows extensions (`brew install sqlite` on
|
||||||
macOS). The gateway sets `INDEX_PATH`/`QMD_CONFIG_DIR` automatically.
|
macOS). The gateway sets `INDEX_PATH`/`QMD_CONFIG_DIR` automatically.
|
||||||
|
- QMD shells out to its CLI, which depends on an Ollama daemon listening on
|
||||||
|
`http://localhost:11434` to load the bundled models (`embeddinggemma`,
|
||||||
|
`ExpedientFalcon/qwen3-reranker:0.6b-q8_0`, `qwen3:0.6b`). Install/run Ollama
|
||||||
|
separately before enabling the backend.
|
||||||
|
- OS support: macOS and Linux work out of the box once Bun + SQLite + Ollama are
|
||||||
|
installed. Windows requires WSL2 (or building the experimental Ollama port)
|
||||||
|
until Ollama ships native binaries.
|
||||||
|
|
||||||
**How the sidecar runs**
|
**How the sidecar runs**
|
||||||
- The gateway writes a self-contained QMD home under
|
- The gateway writes a self-contained QMD home under
|
||||||
|
|||||||
@ -213,13 +213,16 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
||||||
onCloseError: (err) =>
|
onCloseError: (err) =>
|
||||||
defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
||||||
close: (manager) => manager.close(),
|
close: async (manager) => {
|
||||||
|
await manager.close?.();
|
||||||
|
},
|
||||||
run: async (manager) => {
|
run: async (manager) => {
|
||||||
const deep = Boolean(opts.deep || opts.index);
|
const deep = Boolean(opts.deep || opts.index);
|
||||||
let embeddingProbe:
|
let embeddingProbe:
|
||||||
| Awaited<ReturnType<typeof manager.probeEmbeddingAvailability>>
|
| Awaited<ReturnType<typeof manager.probeEmbeddingAvailability>>
|
||||||
| undefined;
|
| undefined;
|
||||||
let indexError: string | undefined;
|
let indexError: string | undefined;
|
||||||
|
const syncFn = manager.sync;
|
||||||
if (deep) {
|
if (deep) {
|
||||||
await withProgress({ label: "Checking memory…", total: 2 }, async (progress) => {
|
await withProgress({ label: "Checking memory…", total: 2 }, async (progress) => {
|
||||||
progress.setLabel("Probing vector…");
|
progress.setLabel("Probing vector…");
|
||||||
@ -229,7 +232,7 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
embeddingProbe = await manager.probeEmbeddingAvailability();
|
embeddingProbe = await manager.probeEmbeddingAvailability();
|
||||||
progress.tick();
|
progress.tick();
|
||||||
});
|
});
|
||||||
if (opts.index) {
|
if (opts.index && syncFn) {
|
||||||
await withProgressTotals(
|
await withProgressTotals(
|
||||||
{
|
{
|
||||||
label: "Indexing memory…",
|
label: "Indexing memory…",
|
||||||
@ -238,7 +241,7 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
},
|
},
|
||||||
async (update, progress) => {
|
async (update, progress) => {
|
||||||
try {
|
try {
|
||||||
await manager.sync({
|
await syncFn({
|
||||||
reason: "cli",
|
reason: "cli",
|
||||||
force: true,
|
force: true,
|
||||||
progress: (syncUpdate) => {
|
progress: (syncUpdate) => {
|
||||||
@ -257,6 +260,8 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} else if (opts.index && !syncFn) {
|
||||||
|
defaultRuntime.log("Memory backend does not support manual reindex.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await manager.probeVectorAvailability();
|
await manager.probeVectorAvailability();
|
||||||
@ -265,11 +270,10 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
const sources = (
|
const sources = (
|
||||||
status.sources?.length ? status.sources : ["memory"]
|
status.sources?.length ? status.sources : ["memory"]
|
||||||
) as MemorySourceName[];
|
) as MemorySourceName[];
|
||||||
const scan = await scanMemorySources({
|
const workspaceDir = status.workspaceDir;
|
||||||
workspaceDir: status.workspaceDir,
|
const scan = workspaceDir
|
||||||
agentId,
|
? await scanMemorySources({ workspaceDir, agentId, sources })
|
||||||
sources,
|
: undefined;
|
||||||
});
|
|
||||||
allResults.push({ agentId, status, embeddingProbe, indexError, scan });
|
allResults.push({ agentId, status, embeddingProbe, indexError, scan });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -291,26 +295,31 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
|
|
||||||
for (const result of allResults) {
|
for (const result of allResults) {
|
||||||
const { agentId, status, embeddingProbe, indexError, scan } = result;
|
const { agentId, status, embeddingProbe, indexError, scan } = result;
|
||||||
|
const filesIndexed = status.files ?? 0;
|
||||||
|
const chunksIndexed = status.chunks ?? 0;
|
||||||
const totalFiles = scan?.totalFiles ?? null;
|
const totalFiles = scan?.totalFiles ?? null;
|
||||||
const indexedLabel =
|
const indexedLabel =
|
||||||
totalFiles === null
|
totalFiles === null
|
||||||
? `${status.files}/? files · ${status.chunks} chunks`
|
? `${filesIndexed}/? files · ${chunksIndexed} chunks`
|
||||||
: `${status.files}/${totalFiles} files · ${status.chunks} chunks`;
|
: `${filesIndexed}/${totalFiles} files · ${chunksIndexed} chunks`;
|
||||||
if (opts.index) {
|
if (opts.index) {
|
||||||
const line = indexError ? `Memory index failed: ${indexError}` : "Memory index complete.";
|
const line = indexError ? `Memory index failed: ${indexError}` : "Memory index complete.";
|
||||||
defaultRuntime.log(line);
|
defaultRuntime.log(line);
|
||||||
}
|
}
|
||||||
|
const requestedProvider = status.requestedProvider ?? status.provider;
|
||||||
|
const modelLabel = status.model ?? status.provider;
|
||||||
|
const storePath = status.dbPath ? shortenHomePath(status.dbPath) : "<unknown>";
|
||||||
|
const workspacePath = status.workspaceDir ? shortenHomePath(status.workspaceDir) : "<unknown>";
|
||||||
|
const sourceList = status.sources?.length ? status.sources.join(", ") : null;
|
||||||
const lines = [
|
const lines = [
|
||||||
`${heading("Memory Search")} ${muted(`(${agentId})`)}`,
|
`${heading("Memory Search")} ${muted(`(${agentId})`)}`,
|
||||||
`${label("Provider")} ${info(status.provider)} ${muted(
|
`${label("Provider")} ${info(status.provider)} ${muted(`(requested: ${requestedProvider})`)}`,
|
||||||
`(requested: ${status.requestedProvider})`,
|
`${label("Model")} ${info(modelLabel)}`,
|
||||||
)}`,
|
sourceList ? `${label("Sources")} ${info(sourceList)}` : null,
|
||||||
`${label("Model")} ${info(status.model)}`,
|
|
||||||
status.sources?.length ? `${label("Sources")} ${info(status.sources.join(", "))}` : null,
|
|
||||||
`${label("Indexed")} ${success(indexedLabel)}`,
|
`${label("Indexed")} ${success(indexedLabel)}`,
|
||||||
`${label("Dirty")} ${status.dirty ? warn("yes") : muted("no")}`,
|
`${label("Dirty")} ${status.dirty ? warn("yes") : muted("no")}`,
|
||||||
`${label("Store")} ${info(shortenHomePath(status.dbPath))}`,
|
`${label("Store")} ${info(storePath)}`,
|
||||||
`${label("Workspace")} ${info(shortenHomePath(status.workspaceDir))}`,
|
`${label("Workspace")} ${info(workspacePath)}`,
|
||||||
].filter(Boolean) as string[];
|
].filter(Boolean) as string[];
|
||||||
if (embeddingProbe) {
|
if (embeddingProbe) {
|
||||||
const state = embeddingProbe.ok ? "ready" : "unavailable";
|
const state = embeddingProbe.ok ? "ready" : "unavailable";
|
||||||
@ -323,7 +332,7 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) {
|
|||||||
if (status.sourceCounts?.length) {
|
if (status.sourceCounts?.length) {
|
||||||
lines.push(label("By source"));
|
lines.push(label("By source"));
|
||||||
for (const entry of status.sourceCounts) {
|
for (const entry of status.sourceCounts) {
|
||||||
const total = scan?.sources.find(
|
const total = scan?.sources?.find(
|
||||||
(scanEntry) => scanEntry.source === entry.source,
|
(scanEntry) => scanEntry.source === entry.source,
|
||||||
)?.totalFiles;
|
)?.totalFiles;
|
||||||
const counts =
|
const counts =
|
||||||
@ -455,9 +464,12 @@ export function registerMemoryCli(program: Command) {
|
|||||||
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
||||||
onCloseError: (err) =>
|
onCloseError: (err) =>
|
||||||
defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
||||||
close: (manager) => manager.close(),
|
close: async (manager) => {
|
||||||
|
await manager.close?.();
|
||||||
|
},
|
||||||
run: async (manager) => {
|
run: async (manager) => {
|
||||||
try {
|
try {
|
||||||
|
const syncFn = manager.sync;
|
||||||
if (opts.verbose) {
|
if (opts.verbose) {
|
||||||
const status = manager.status();
|
const status = manager.status();
|
||||||
const rich = isRich();
|
const rich = isRich();
|
||||||
@ -466,15 +478,17 @@ export function registerMemoryCli(program: Command) {
|
|||||||
const info = (text: string) => colorize(rich, theme.info, text);
|
const info = (text: string) => colorize(rich, theme.info, text);
|
||||||
const warn = (text: string) => colorize(rich, theme.warn, text);
|
const warn = (text: string) => colorize(rich, theme.warn, text);
|
||||||
const label = (text: string) => muted(`${text}:`);
|
const label = (text: string) => muted(`${text}:`);
|
||||||
const sourceLabels = status.sources.map((source) =>
|
const sourceLabels = (status.sources ?? []).map((source) =>
|
||||||
formatSourceLabel(source, status.workspaceDir, agentId),
|
formatSourceLabel(source, status.workspaceDir ?? "", agentId),
|
||||||
);
|
);
|
||||||
|
const requestedProvider = status.requestedProvider ?? status.provider;
|
||||||
|
const modelLabel = status.model ?? status.provider;
|
||||||
const lines = [
|
const lines = [
|
||||||
`${heading("Memory Index")} ${muted(`(${agentId})`)}`,
|
`${heading("Memory Index")} ${muted(`(${agentId})`)}`,
|
||||||
`${label("Provider")} ${info(status.provider)} ${muted(
|
`${label("Provider")} ${info(status.provider)} ${muted(
|
||||||
`(requested: ${status.requestedProvider})`,
|
`(requested: ${requestedProvider})`,
|
||||||
)}`,
|
)}`,
|
||||||
`${label("Model")} ${info(status.model)}`,
|
`${label("Model")} ${info(modelLabel)}`,
|
||||||
sourceLabels.length
|
sourceLabels.length
|
||||||
? `${label("Sources")} ${info(sourceLabels.join(", "))}`
|
? `${label("Sources")} ${info(sourceLabels.join(", "))}`
|
||||||
: null,
|
: null,
|
||||||
@ -514,6 +528,10 @@ export function registerMemoryCli(program: Command) {
|
|||||||
? `${lastLabel} · elapsed ${elapsed} · eta ${eta}`
|
? `${lastLabel} · elapsed ${elapsed} · eta ${eta}`
|
||||||
: `${lastLabel} · elapsed ${elapsed}`;
|
: `${lastLabel} · elapsed ${elapsed}`;
|
||||||
};
|
};
|
||||||
|
if (!syncFn) {
|
||||||
|
defaultRuntime.log("Memory backend does not support manual reindex.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await withProgressTotals(
|
await withProgressTotals(
|
||||||
{
|
{
|
||||||
label: "Indexing memory…",
|
label: "Indexing memory…",
|
||||||
@ -525,7 +543,7 @@ export function registerMemoryCli(program: Command) {
|
|||||||
progress.setLabel(buildLabel());
|
progress.setLabel(buildLabel());
|
||||||
}, 1000);
|
}, 1000);
|
||||||
try {
|
try {
|
||||||
await manager.sync({
|
await syncFn({
|
||||||
reason: "cli",
|
reason: "cli",
|
||||||
force: true,
|
force: true,
|
||||||
progress: (syncUpdate) => {
|
progress: (syncUpdate) => {
|
||||||
@ -579,7 +597,9 @@ export function registerMemoryCli(program: Command) {
|
|||||||
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
|
||||||
onCloseError: (err) =>
|
onCloseError: (err) =>
|
||||||
defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
|
||||||
close: (manager) => manager.close(),
|
close: async (manager) => {
|
||||||
|
await manager.close?.();
|
||||||
|
},
|
||||||
run: async (manager) => {
|
run: async (manager) => {
|
||||||
let results: Awaited<ReturnType<typeof manager.search>>;
|
let results: Awaited<ReturnType<typeof manager.search>>;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -84,10 +84,14 @@ export async function resolveDiscordTarget(
|
|||||||
|
|
||||||
const likelyUsername = isLikelyUsername(trimmed);
|
const likelyUsername = isLikelyUsername(trimmed);
|
||||||
const shouldLookup = isExplicitUserLookup(trimmed, parseOptions) || likelyUsername;
|
const shouldLookup = isExplicitUserLookup(trimmed, parseOptions) || likelyUsername;
|
||||||
|
|
||||||
|
// Parse directly if it's already a known format. Use a safe parse so ambiguous
|
||||||
|
// numeric targets don't throw when we still want to attempt username lookup.
|
||||||
const directParse = safeParseDiscordTarget(trimmed, parseOptions);
|
const directParse = safeParseDiscordTarget(trimmed, parseOptions);
|
||||||
if (directParse && directParse.kind !== "channel" && !likelyUsername) {
|
if (directParse && directParse.kind !== "channel" && !likelyUsername) {
|
||||||
return directParse;
|
return directParse;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldLookup) {
|
if (!shouldLookup) {
|
||||||
return directParse ?? parseDiscordTarget(trimmed, parseOptions);
|
return directParse ?? parseDiscordTarget(trimmed, parseOptions);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ import type {
|
|||||||
MemorySource,
|
MemorySource,
|
||||||
MemorySyncProgressUpdate,
|
MemorySyncProgressUpdate,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
|
|
||||||
|
type SqliteDatabase = import("node:sqlite").DatabaseSync;
|
||||||
import type { ResolvedMemoryBackendConfig, ResolvedQmdConfig } from "./backend-config.js";
|
import type { ResolvedMemoryBackendConfig, ResolvedQmdConfig } from "./backend-config.js";
|
||||||
|
|
||||||
const log = createSubsystemLogger("memory");
|
const log = createSubsystemLogger("memory");
|
||||||
@ -85,7 +87,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
|||||||
private updateTimer: NodeJS.Timeout | null = null;
|
private updateTimer: NodeJS.Timeout | null = null;
|
||||||
private pendingUpdate: Promise<void> | null = null;
|
private pendingUpdate: Promise<void> | null = null;
|
||||||
private closed = false;
|
private closed = false;
|
||||||
private db: import("node:sqlite").DatabaseSync | null = null;
|
private db: SqliteDatabase | null = null;
|
||||||
private lastUpdateAt: number | null = null;
|
private lastUpdateAt: number | null = null;
|
||||||
|
|
||||||
private constructor(params: {
|
private constructor(params: {
|
||||||
@ -379,10 +381,10 @@ export class QmdMemoryManager implements MemorySearchManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ensureDb() {
|
private ensureDb(): SqliteDatabase {
|
||||||
if (this.db) return this.db;
|
if (this.db) return this.db;
|
||||||
const sqlite = requireNodeSqlite();
|
const { DatabaseSync } = requireNodeSqlite();
|
||||||
this.db = sqlite.open(this.indexPath, { readonly: true });
|
this.db = new DatabaseSync(this.indexPath, { readOnly: true });
|
||||||
return this.db;
|
return this.db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user