mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-10 22:15:57 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
146
openclaw/extensions/telegram/src/sticker-cache.ts
Normal file
146
openclaw/extensions/telegram/src/sticker-cache.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { ModelCatalogEntry } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import {
|
||||
findModelInCatalog,
|
||||
loadModelCatalog,
|
||||
modelSupportsVision,
|
||||
} from "openclaw/plugin-sdk/agent-runtime";
|
||||
import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { resolveAutoImageModel } from "openclaw/plugin-sdk/media-runtime";
|
||||
import {
|
||||
resolveAutoMediaKeyProviders,
|
||||
resolveDefaultMediaModel,
|
||||
} from "openclaw/plugin-sdk/media-runtime";
|
||||
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { getTelegramRuntime } from "./runtime.js";
|
||||
export {
|
||||
cacheSticker,
|
||||
getAllCachedStickers,
|
||||
getCachedSticker,
|
||||
getCacheStats,
|
||||
searchStickers,
|
||||
type CachedSticker,
|
||||
} from "./sticker-cache-store.js";
|
||||
|
||||
const STICKER_DESCRIPTION_PROMPT =
|
||||
"Describe this sticker image in 1-2 sentences. Focus on what the sticker depicts (character, object, action, emotion). Be concise and objective.";
|
||||
|
||||
export interface DescribeStickerParams {
|
||||
imagePath: string;
|
||||
cfg: OpenClawConfig;
|
||||
agentDir?: string;
|
||||
agentId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe a sticker image using vision API.
|
||||
* Auto-detects an available vision provider based on configured API keys.
|
||||
* Returns null if no vision provider is available.
|
||||
*/
|
||||
export async function describeStickerImage(params: DescribeStickerParams): Promise<string | null> {
|
||||
const { imagePath, cfg, agentDir, agentId } = params;
|
||||
|
||||
const defaultModel = resolveDefaultModelForAgent({ cfg, agentId });
|
||||
let activeModel = undefined as { provider: string; model: string } | undefined;
|
||||
let catalog: ModelCatalogEntry[] = [];
|
||||
try {
|
||||
catalog = await loadModelCatalog({ config: cfg });
|
||||
const entry = findModelInCatalog(catalog, defaultModel.provider, defaultModel.model);
|
||||
const supportsVision = modelSupportsVision(entry);
|
||||
if (supportsVision) {
|
||||
activeModel = { provider: defaultModel.provider, model: defaultModel.model };
|
||||
}
|
||||
} catch {
|
||||
// Ignore catalog failures; fall back to auto selection.
|
||||
}
|
||||
|
||||
const hasProviderKey = async (provider: string) => {
|
||||
try {
|
||||
await resolveApiKeyForProvider({ provider, cfg, agentDir });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const autoProviders = resolveAutoMediaKeyProviders({
|
||||
cfg,
|
||||
capability: "image",
|
||||
});
|
||||
|
||||
const selectCatalogModel = (provider: string) => {
|
||||
const entries = catalog.filter(
|
||||
(entry) =>
|
||||
normalizeLowercaseStringOrEmpty(entry.provider) ===
|
||||
normalizeLowercaseStringOrEmpty(provider) && modelSupportsVision(entry),
|
||||
);
|
||||
if (entries.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const defaultId = resolveDefaultMediaModel({
|
||||
cfg,
|
||||
providerId: provider,
|
||||
capability: "image",
|
||||
});
|
||||
const preferred = entries.find((entry) => entry.id === defaultId);
|
||||
return preferred ?? entries[0];
|
||||
};
|
||||
|
||||
let resolved = null as { provider: string; model?: string } | null;
|
||||
if (
|
||||
activeModel &&
|
||||
autoProviders.includes(activeModel.provider) &&
|
||||
(await hasProviderKey(activeModel.provider))
|
||||
) {
|
||||
resolved = activeModel;
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
for (const provider of autoProviders) {
|
||||
if (!(await hasProviderKey(provider))) {
|
||||
continue;
|
||||
}
|
||||
const entry = selectCatalogModel(provider);
|
||||
if (entry) {
|
||||
resolved = { provider, model: entry.id };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
resolved = await resolveAutoImageModel({
|
||||
cfg,
|
||||
agentDir,
|
||||
activeModel,
|
||||
});
|
||||
}
|
||||
|
||||
if (!resolved?.model) {
|
||||
logVerbose("telegram: no vision provider available for sticker description");
|
||||
return null;
|
||||
}
|
||||
|
||||
const { provider, model } = resolved;
|
||||
logVerbose(`telegram: describing sticker with ${provider}/${model}`);
|
||||
|
||||
try {
|
||||
const result = await getTelegramRuntime().mediaUnderstanding.describeImageFileWithModel({
|
||||
filePath: imagePath,
|
||||
mime: "image/webp",
|
||||
cfg,
|
||||
agentDir,
|
||||
provider,
|
||||
model,
|
||||
prompt: STICKER_DESCRIPTION_PROMPT,
|
||||
maxTokens: 150,
|
||||
timeoutMs: 30_000,
|
||||
});
|
||||
return result.text ?? null;
|
||||
} catch (err) {
|
||||
logVerbose(`telegram: failed to describe sticker: ${String(err)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue