refactor(agents): share model manifest context

This commit is contained in:
Peter Steinberger
2026-05-17 02:23:42 +01:00
parent da8afe359d
commit 7ee5fe011b
7 changed files with 85 additions and 88 deletions

View File

@@ -73,6 +73,7 @@ import { AGENT_LANE_SUBAGENT } from "./lanes.js";
import { LiveSessionModelSwitchError } from "./live-model-switch.js";
import { loadManifestModelCatalog } from "./model-catalog.js";
import { runWithModelFallback } from "./model-fallback.js";
import type { ModelManifestNormalizationContext } from "./model-selection-normalize.js";
import {
buildConfiguredModelCatalog,
modelKey,
@@ -402,17 +403,19 @@ async function prepareAgentCommandExecution(
workspaceDir,
env: process.env,
});
const manifestPlugins = manifestMetadataSnapshot.plugins;
const modelManifestContext = {
manifestPlugins: manifestMetadataSnapshot.plugins,
} satisfies ModelManifestNormalizationContext;
const configuredModel = resolveConfiguredModelRef({
cfg,
defaultProvider: DEFAULT_PROVIDER,
defaultModel: DEFAULT_MODEL,
manifestPlugins,
...modelManifestContext,
});
const configuredThinkingCatalog = buildConfiguredModelCatalog({
cfg,
workspaceDir,
manifestPlugins,
...modelManifestContext,
});
const thinkingLevelsHint = formatThinkingLevels(
configuredModel.provider,
@@ -472,7 +475,7 @@ async function prepareAgentCommandExecution(
outboundSession,
workspaceDir,
agentDir,
manifestPlugins,
modelManifestContext,
runId,
acpManager,
acpResolution,
@@ -512,7 +515,7 @@ async function agentCommandInternal(
runId,
acpManager,
acpResolution,
manifestPlugins,
modelManifestContext,
} = prepared;
let sessionEntry = prepared.sessionEntry;
@@ -764,12 +767,12 @@ async function agentCommandInternal(
const configuredDefaultRef = resolveDefaultModelForAgent({
cfg,
agentId: sessionAgentId,
manifestPlugins,
...modelManifestContext,
});
const { provider: defaultProvider, model: defaultModel } = normalizeModelRef(
configuredDefaultRef.provider,
configuredDefaultRef.model,
{ manifestPlugins },
modelManifestContext,
);
let provider = defaultProvider;
let model = defaultModel;
@@ -802,7 +805,7 @@ async function agentCommandInternal(
catalog: [],
defaultProvider,
defaultModel,
manifestPlugins,
...modelManifestContext,
});
if (needsModelCatalog) {
@@ -813,7 +816,7 @@ async function agentCommandInternal(
defaultProvider,
defaultModel,
agentId: sessionAgentId,
manifestPlugins,
...modelManifestContext,
});
allowedModelCatalog = visibilityPolicy.allowedCatalog;
}
@@ -836,9 +839,11 @@ async function agentCommandInternal(
const overrideProvider = sessionEntry.providerOverride?.trim() || defaultProvider;
const overrideModel = sessionEntry.modelOverride?.trim();
if (overrideModel) {
const normalizedOverride = normalizeModelRef(overrideProvider, overrideModel, {
manifestPlugins,
});
const normalizedOverride = normalizeModelRef(
overrideProvider,
overrideModel,
modelManifestContext,
);
const key = modelKey(normalizedOverride.provider, normalizedOverride.model);
if (!visibilityPolicy.allowsKey(key)) {
const { updated } = applyModelOverrideToSessionEntry({
@@ -861,9 +866,11 @@ async function agentCommandInternal(
let storedModelOverride = sessionEntry?.modelOverride?.trim();
if (storedModelOverride) {
const candidateProvider = storedProviderOverride || defaultProvider;
const normalizedStored = normalizeModelRef(candidateProvider, storedModelOverride, {
manifestPlugins,
});
const normalizedStored = normalizeModelRef(
candidateProvider,
storedModelOverride,
modelManifestContext,
);
const key = modelKey(normalizedStored.provider, normalizedStored.model);
if (visibilityPolicy.allowsKey(key)) {
provider = normalizedStored.provider;
@@ -889,10 +896,10 @@ async function agentCommandInternal(
if (hasExplicitRunOverride) {
const explicitRef = explicitModelOverride
? explicitProviderOverride
? normalizeModelRef(explicitProviderOverride, explicitModelOverride, { manifestPlugins })
: parseModelRef(explicitModelOverride, provider, { manifestPlugins })
? normalizeModelRef(explicitProviderOverride, explicitModelOverride, modelManifestContext)
: parseModelRef(explicitModelOverride, provider, modelManifestContext)
: explicitProviderOverride
? normalizeModelRef(explicitProviderOverride, model, { manifestPlugins })
? normalizeModelRef(explicitProviderOverride, model, modelManifestContext)
: null;
if (!explicitRef) {
throw new Error("Invalid model override.");
@@ -1107,7 +1114,7 @@ async function agentCommandInternal(
cfg,
provider,
model,
manifestPlugins,
...modelManifestContext,
runId,
agentDir,
fallbacksOverride: effectiveFallbacksOverride,
@@ -1299,7 +1306,7 @@ async function agentCommandInternal(
{ cause: err },
);
}
const switchRef = normalizeModelRef(err.provider, err.model, { manifestPlugins });
const switchRef = normalizeModelRef(err.provider, err.model, modelManifestContext);
const switchKey = modelKey(switchRef.provider, switchRef.model);
if (!visibilityPolicy.allowsKey(switchKey)) {
log.info(

View File

@@ -6,7 +6,6 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
import { emitFailoverEvent } from "../infra/diagnostic-events.js";
import { formatErrorMessage } from "../infra/errors.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import { isCommandLaneTaskTimeoutError } from "../process/command-queue.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
@@ -35,7 +34,11 @@ import {
type ModelFallbackStepFields,
} from "./model-fallback-observation.js";
import type { FallbackAttempt, ModelCandidate } from "./model-fallback.types.js";
import { modelKey, normalizeModelRef } from "./model-selection-normalize.js";
import {
type ModelManifestNormalizationContext,
modelKey,
normalizeModelRef,
} from "./model-selection-normalize.js";
import {
buildConfiguredAllowlistKeys,
buildModelAliasIndex,
@@ -94,10 +97,6 @@ type ModelFallbackRunFn<T> = (
options?: ModelFallbackRunOptions,
) => Promise<T>;
type ManifestNormalizationContext = {
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
};
/**
* Fallback abort check. Only treats explicit AbortError names as user aborts.
* Message-based checks (e.g., "aborted") can mask timeouts and skip fallback.
@@ -485,7 +484,7 @@ function resolveImageFallbackCandidates(
cfg: OpenClawConfig | undefined;
defaultProvider: string;
modelOverride?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelCandidate[] {
const aliasIndex = buildModelAliasIndex({
cfg: params.cfg ?? {},
@@ -570,7 +569,7 @@ function resolveFallbackCandidates(
model: string;
/** Optional explicit fallbacks list; when provided (even empty), replaces agents.defaults.model.fallbacks. */
fallbacksOverride?: string[];
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelCandidate[] {
const primary = params.cfg
? resolveConfiguredModelRef({
@@ -851,7 +850,7 @@ export async function runWithModelFallback<T>(
onError?: ModelFallbackErrorHandler;
onFallbackStep?: ModelFallbackStepHandler;
classifyResult?: ModelFallbackResultClassifier<T>;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): Promise<ModelFallbackRunResult<T>> {
const candidates = resolveFallbackCandidates({
cfg: params.cfg,

View File

@@ -14,6 +14,10 @@ export type ModelRef = {
model: string;
};
export type ModelManifestNormalizationContext = {
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
};
export function modelKey(provider: string, model: string) {
return sharedModelKey(provider, model);
}
@@ -39,10 +43,9 @@ export {
function normalizeProviderModelId(
provider: string,
model: string,
options?: {
options?: ModelManifestNormalizationContext & {
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
},
): string {
const staticModelId = normalizeStaticProviderModelId(provider, model, {
@@ -63,10 +66,9 @@ function normalizeProviderModelId(
);
}
type ModelRefNormalizeOptions = {
type ModelRefNormalizeOptions = ModelManifestNormalizationContext & {
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
};
export function normalizeModelRef(

View File

@@ -1,8 +1,7 @@
import { resolveAgentModelFallbackValues } from "../config/model-input.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import type { ModelCatalogEntry } from "./model-catalog.types.js";
import type { ModelRef } from "./model-selection-normalize.js";
import type { ModelManifestNormalizationContext, ModelRef } from "./model-selection-normalize.js";
import {
buildModelAliasIndex,
getModelRefStatusWithFallbackModels,
@@ -20,10 +19,6 @@ export {
} from "./model-selection-shared.js";
export type { ModelRefStatus } from "./model-selection-shared.js";
type ManifestNormalizationContext = {
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
};
function resolveDefaultFallbackModels(cfg: OpenClawConfig): string[] {
return resolveAgentModelFallbackValues(cfg.agents?.defaults?.model);
}
@@ -35,7 +30,7 @@ export function getModelRefStatus(
ref: ModelRef;
defaultProvider: string;
defaultModel?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRefStatus {
const { cfg, catalog, ref, defaultProvider, defaultModel, manifestPlugins } = params;
return getModelRefStatusWithFallbackModels({
@@ -56,7 +51,7 @@ export function resolveAllowedModelRef(
raw: string;
defaultProvider: string;
defaultModel?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
):
| { ref: ModelRef; key: string }
| {

View File

@@ -3,7 +3,6 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { getCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js";
import { loadManifestMetadataSnapshot } from "../plugins/manifest-contract-eligibility.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import { getActivePluginRegistryWorkspaceDirFromState } from "../plugins/runtime-state.js";
import {
normalizeLowercaseStringOrEmpty,
@@ -20,6 +19,7 @@ import {
normalizeStaticProviderModelId,
} from "./model-ref-shared.js";
import {
type ModelManifestNormalizationContext,
type ModelRef,
findNormalizedProviderValue,
modelKey,
@@ -36,16 +36,13 @@ function getLog(): ReturnType<typeof createSubsystemLogger> {
}
const OPENROUTER_COMPAT_FREE_ALIAS = "openrouter:free";
type ModelManifestPlugins = ModelManifestNormalizationContext["manifestPlugins"];
export type ModelAliasIndex = {
byAlias: Map<string, { alias: string; ref: ModelRef }>;
byKey: Map<string, string[]>;
};
type ManifestNormalizationContext = {
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
};
function sanitizeModelWarningValue(value: string): string {
const stripped = value ? stripAnsi(value) : "";
let controlBoundary = -1;
@@ -83,7 +80,7 @@ export function inferUniqueProviderFromConfiguredModels(
params: {
cfg: OpenClawConfig;
model: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): string | undefined {
const model = params.model.trim();
if (!model) {
@@ -189,7 +186,7 @@ export function resolveBareModelDefaultProvider(
catalog: readonly ModelCatalogEntry[];
model: string;
defaultProvider: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): string {
return (
inferUniqueProviderFromConfiguredModels({
@@ -212,7 +209,7 @@ function resolveConfiguredOpenRouterCompatFreeRef(
defaultProvider: string;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef | null {
const configuredModels = params.cfg.agents?.defaults?.models ?? {};
for (const raw of Object.keys(configuredModels)) {
@@ -255,7 +252,7 @@ export function resolveConfiguredOpenRouterCompatAlias(
defaultProvider: string;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef | null {
const normalized = normalizeLowercaseStringOrEmpty(params.raw);
if (normalized === "openrouter:auto") {
@@ -284,7 +281,7 @@ function parseModelRefWithCompatAlias(
defaultProvider: string;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef | null {
return (
resolveConfiguredOpenRouterCompatAlias(params) ??
@@ -303,7 +300,7 @@ function resolveExactConfiguredProviderRef(
raw: string;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef | null {
const slash = params.raw.indexOf("/");
if (slash <= 0 || !params.cfg?.models?.providers) {
@@ -350,7 +347,7 @@ export function resolveAllowlistModelKey(
cfg?: OpenClawConfig;
raw: string;
defaultProvider: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): string | null {
const parsed = parseModelRefWithCompatAlias({
cfg: params.cfg,
@@ -368,7 +365,7 @@ export function buildConfiguredAllowlistKeys(
params: {
cfg: OpenClawConfig | undefined;
defaultProvider: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): Set<string> | null {
const visibility = parseConfiguredModelVisibilityEntries({ cfg: params.cfg });
if (visibility.exactModelRefs.length === 0) {
@@ -396,7 +393,7 @@ export function buildModelAliasIndex(
defaultProvider: string;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelAliasIndex {
const byAlias = new Map<string, { alias: string; ref: ModelRef }>();
const byKey = new Map<string, string[]>();
@@ -443,7 +440,7 @@ function buildModelCatalogMetadata(
params: {
cfg: OpenClawConfig;
defaultProvider: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelCatalogMetadata {
const configuredByKey = new Map<string, ModelCatalogEntry>();
for (const entry of buildConfiguredModelCatalog({
@@ -538,7 +535,7 @@ export function resolveModelRefFromString(
aliasIndex?: ModelAliasIndex;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): { ref: ModelRef; alias?: string } | null {
const { model } = splitTrailingAuthProfile(params.raw);
if (!model) {
@@ -570,7 +567,7 @@ export function resolveConfiguredModelRef(
defaultModel: string;
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef {
const rawModel = resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model) ?? "";
if (rawModel) {
@@ -658,7 +655,7 @@ export function buildAllowedModelSetWithFallbacks(
fallbackModels: readonly string[];
allowManifestNormalization?: boolean;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): {
allowAny: boolean;
allowedCatalog: ModelCatalogEntry[];
@@ -857,7 +854,7 @@ export function getModelRefStatusWithFallbackModels(
defaultProvider: string;
defaultModel?: string;
fallbackModels: readonly string[];
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRefStatus {
const allowed = buildAllowedModelSetWithFallbacks({
cfg: params.cfg,
@@ -881,7 +878,7 @@ export function resolveAllowedModelRefFromAliasIndex(
defaultProvider: string;
aliasIndex: ModelAliasIndex;
getStatus: (ref: ModelRef) => ModelRefStatus;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ResolveAllowedModelRefResult {
const trimmed = params.raw.trim();
if (!trimmed) {
@@ -926,8 +923,8 @@ export function hasConfiguredProviderModelRows(cfg: OpenClawConfig): boolean {
function resolveConfiguredModelManifestPlugins(params: {
cfg: OpenClawConfig;
workspaceDir?: string;
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
}): readonly Pick<PluginManifestRecord, "modelIdNormalization">[] | undefined {
manifestPlugins?: ModelManifestPlugins;
}): ModelManifestPlugins {
if (params.manifestPlugins) {
return params.manifestPlugins;
}
@@ -953,7 +950,7 @@ function resolveConfiguredModelManifestPlugins(params: {
export function buildConfiguredModelCatalog(params: {
cfg: OpenClawConfig;
workspaceDir?: string;
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
manifestPlugins?: ModelManifestPlugins;
}): ModelCatalogEntry[] {
const providers = params.cfg.models?.providers;
if (!providers || typeof providers !== "object") {
@@ -1007,7 +1004,7 @@ export function resolveHooksGmailModel(
params: {
cfg: OpenClawConfig;
defaultProvider: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef | null {
const hooksModel = params.cfg.hooks?.gmail?.model;
if (!hooksModel?.trim()) {
@@ -1099,7 +1096,7 @@ export function resolveAllowedModelSelection(
allowAny: boolean;
allowedKeys: ReadonlySet<string>;
allowedCatalog: readonly ModelCatalogEntry[];
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef | null {
const current = normalizeModelRef(params.provider, params.model, {
manifestPlugins: params.manifestPlugins,
@@ -1158,7 +1155,7 @@ export function createModelVisibilityPolicyWithFallbacks(
defaultProvider: string;
defaultModel?: string;
fallbackModels: readonly string[];
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelVisibilityPolicy {
const visibility = parseConfiguredModelVisibilityEntries({ cfg: params.cfg });
const allowed = buildAllowedModelSetWithFallbacks(params);

View File

@@ -4,7 +4,6 @@ import {
toAgentModelListLike,
} from "../config/model-input.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
@@ -23,6 +22,7 @@ export {
resolveThinkingDefaultWithRuntimeCatalog,
} from "./model-thinking-default.js";
import {
type ModelManifestNormalizationContext,
type ModelRef,
findNormalizedProviderKey,
findNormalizedProviderValue,
@@ -53,11 +53,7 @@ import {
type ModelRefStatus,
} from "./model-selection-shared.js";
export type { ModelAliasIndex, ModelRef, ModelRefStatus };
type ManifestNormalizationContext = {
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
};
export type { ModelAliasIndex, ModelManifestNormalizationContext, ModelRef, ModelRefStatus };
export type ThinkLevel =
| "off"
@@ -210,7 +206,7 @@ export function resolveAllowlistModelKey(
raw: string,
defaultProvider: string,
cfg?: OpenClawConfig,
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[],
manifestPlugins?: ModelManifestNormalizationContext["manifestPlugins"],
): string | null {
return resolveAllowlistModelKeyFromShared({ cfg, raw, defaultProvider, manifestPlugins });
}
@@ -220,7 +216,7 @@ export function resolveDefaultModelForAgent(
cfg: OpenClawConfig;
agentId?: string;
allowPluginNormalization?: boolean;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRef {
const agentModelOverride = params.agentId
? resolveAgentEffectiveModelPrimary(params.cfg, params.agentId)
@@ -387,7 +383,7 @@ export function buildAllowedModelSet(
defaultProvider: string;
defaultModel?: string;
agentId?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): {
allowAny: boolean;
allowedCatalog: ModelCatalogEntry[];
@@ -413,7 +409,7 @@ export function getModelRefStatus(
ref: ModelRef;
defaultProvider: string;
defaultModel?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
): ModelRefStatus {
return getModelRefStatusWithFallbackModels({
cfg: params.cfg,
@@ -434,7 +430,7 @@ function getModelRefStatusForResolve(
catalog: ModelCatalogEntry[];
defaultProvider: string;
defaultModel?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
ref: ModelRef,
): ModelRefStatus {
return getModelRefStatus({
@@ -454,7 +450,7 @@ export function resolveAllowedModelRef(
raw: string;
defaultProvider: string;
defaultModel?: string;
} & ManifestNormalizationContext,
} & ModelManifestNormalizationContext,
):
| { ref: ModelRef; key: string }
| {

View File

@@ -1,8 +1,8 @@
import { resolveAgentModelFallbackValues } from "../config/model-input.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import { resolveAgentModelFallbacksOverride } from "./agent-scope.js";
import type { ModelCatalogEntry } from "./model-catalog.types.js";
import type { ModelManifestNormalizationContext } from "./model-selection-normalize.js";
import {
createModelVisibilityPolicyWithFallbacks,
type ModelVisibilityPolicy,
@@ -18,14 +18,15 @@ function resolveAllowedFallbacks(params: { cfg: OpenClawConfig; agentId?: string
return resolveAgentModelFallbackValues(params.cfg.agents?.defaults?.model);
}
export function createModelVisibilityPolicy(params: {
cfg: OpenClawConfig;
catalog: ModelCatalogEntry[];
defaultProvider: string;
defaultModel?: string;
agentId?: string;
manifestPlugins?: readonly Pick<PluginManifestRecord, "modelIdNormalization">[];
}): ModelVisibilityPolicy {
export function createModelVisibilityPolicy(
params: {
cfg: OpenClawConfig;
catalog: ModelCatalogEntry[];
defaultProvider: string;
defaultModel?: string;
agentId?: string;
} & ModelManifestNormalizationContext,
): ModelVisibilityPolicy {
return createModelVisibilityPolicyWithFallbacks({
cfg: params.cfg,
catalog: params.catalog,