openclaw / src /cli /capability-cli /embedding.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f778c12 verified
Raw
History Blame Contribute Delete
6.71 kB
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import type { Command } from "commander";
import { resolveAgentDir } from "../../agents/agent-scope.js";
import { resolveMemorySearchConfig } from "../../agents/memory-search.js";
import { createEmbeddingProvider } from "../../plugin-sdk/memory-core-bundled-runtime.js";
import { listEmbeddingProviders } from "../../plugins/embedding-provider-runtime.js";
import { listRegisteredMemoryEmbeddingProviderAdapters } from "../../plugins/memory-embedding-provider-runtime.js";
import { defaultRuntime } from "../../runtime.js";
import { runCommandWithRuntime } from "../cli-utils.js";
import { getMemoryEmbeddingCommandSecretTargetIds } from "../command-secret-targets.js";
import { collectOption } from "../program/helpers.js";
import { prepareLocalCapabilityAccountSecrets } from "./local-account-secrets.js";
import type { CapabilityEnvelope } from "./metadata.js";
import { emitJsonOrText, formatEnvelopeForText, providerSummaryText } from "./output.js";
import {
providerHasGenericConfig,
registerLocalProvidersCommand,
requireProviderModelOverride,
resolveCapabilityAgentOption,
resolveCapabilityProviderAgentId,
resolveLocalCapabilityRuntimeConfig,
} from "./shared.js";
async function closeEmbeddingProviderWithRetry(provider: {
close?: () => Promise<void> | void;
}): Promise<void> {
let lastError: unknown;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
await provider.close?.();
return;
} catch (err) {
lastError = err;
}
}
throw lastError;
}
async function runMemoryEmbeddingCreate(params: {
texts: string[];
provider?: string;
model?: string;
agent?: string;
}) {
const modelRef = requireProviderModelOverride(params.model);
const cfg = await resolveLocalCapabilityRuntimeConfig({
commandName: "infer embedding create",
targetIds: getMemoryEmbeddingCommandSecretTargetIds(),
});
const requestedProvider =
normalizeOptionalString(params.provider) || modelRef?.provider || "auto";
const agentId = resolveCapabilityProviderAgentId(cfg, params.agent, "infer embedding create");
await prepareLocalCapabilityAccountSecrets({ cfg, agentId });
const result = await createEmbeddingProvider({
config: cfg,
agentDir: resolveAgentDir(cfg, agentId),
provider: requestedProvider,
fallback: "none",
model: modelRef?.model ?? "",
});
if (!result.provider) {
throw new Error(result.providerUnavailableReason ?? "No embedding provider available.");
}
const provider = result.provider;
let embeddings: number[][] = [];
let operationError: unknown;
let operationFailed = false;
try {
embeddings = await provider.embedBatch(params.texts, { inputType: "document" });
} catch (err) {
operationError = err;
operationFailed = true;
}
let closeError: unknown;
let closeFailed = false;
try {
await closeEmbeddingProviderWithRetry(provider);
} catch (err) {
closeError = err;
closeFailed = true;
}
if (operationFailed) {
throw operationError;
}
if (closeFailed) {
throw closeError;
}
return {
ok: true,
capability: "embedding.create",
transport: "local" as const,
provider: provider.id,
model: provider.model,
attempts: result.fallbackFrom
? [{ provider: result.fallbackFrom, outcome: "failed", error: result.fallbackReason }]
: [],
outputs: embeddings.map((embedding, index) => ({
text: params.texts[index],
embedding,
dimensions: embedding.length,
})),
} satisfies CapabilityEnvelope;
}
export function registerEmbeddingCapabilityCommands(capability: Command): void {
const embedding = capability
.command("embedding")
.description("Embedding providers")
.option("--agent <id>", "Agent whose model and auth state should be used");
embedding
.command("create")
.description("Create embeddings")
.requiredOption("--text <text>", "Input text", collectOption)
.option("--provider <id>", "Provider id")
.option("--model <provider/model>", "Model override")
.option(
"--agent <id>",
"Agent whose saved provider auth is used (default: agents.defaults.systemAgent.agentId, then the sole agent)",
)
.option("--json", "Output JSON", false)
.action(async (opts, command) => {
await runCommandWithRuntime(defaultRuntime, async () => {
const result = await runMemoryEmbeddingCreate({
texts: opts.text as string[],
agent: resolveCapabilityAgentOption(command, opts.agent),
provider: opts.provider as string | undefined,
model: opts.model as string | undefined,
});
emitJsonOrText(defaultRuntime, Boolean(opts.json), result, formatEnvelopeForText);
});
});
registerLocalProvidersCommand(
embedding,
"List embedding providers",
(cfg, agentId) => {
const resolvedMemory = resolveMemorySearchConfig(cfg, agentId);
const selectedProvider = resolvedMemory?.provider;
const providers = new Map(
listRegisteredMemoryEmbeddingProviderAdapters().map((provider) => [
provider.id,
{
id: provider.id,
defaultModel: provider.defaultModel,
transport: provider.transport,
autoSelectPriority: provider.autoSelectPriority,
},
]),
);
for (const provider of listEmbeddingProviders(cfg)) {
if (providers.has(provider.id)) {
continue;
}
providers.set(provider.id, {
id: provider.id,
defaultModel: provider.defaultModel,
transport: provider.transport,
autoSelectPriority: undefined,
});
}
if (selectedProvider && !providers.has(selectedProvider)) {
providers.set(selectedProvider, {
id: selectedProvider,
defaultModel: resolvedMemory?.model || undefined,
transport: providerHasGenericConfig({ cfg, providerId: selectedProvider, agentId })
? "remote"
: undefined,
autoSelectPriority: undefined,
});
}
return Array.from(providers.values()).map((provider) => ({
available: true,
configured:
provider.id === selectedProvider ||
providerHasGenericConfig({
cfg,
providerId: provider.id,
agentId,
}),
selected: provider.id === selectedProvider,
id: provider.id,
defaultModel: provider.defaultModel,
transport: provider.transport,
autoSelectPriority: provider.autoSelectPriority,
}));
},
providerSummaryText,
);
}