/**
 * The default config tree. Mirrors `schema.ts` exactly. When merging YAML,
 * we deep-merge over this tree so users only need to specify what they want
 * to change.
 */
export const DEFAULT_CONFIG = {
    version: 1,
    viewer: {
        // Per-agent default lives in `templates/config.<agent>.yaml`:
        //   - openclaw → 18799
        //   - hermes   → 18800
        // The fallback here only matters when neither config file exists
        // (early bootstrap, tests, etc.).
        port: 18799,
        bindHost: "127.0.0.1",
        openOnFirstTurn: false,
    },
    bridge: {
        port: 18911,
        mode: "stdio",
    },
    embedding: {
        provider: "local",
        endpoint: "",
        model: "Xenova/all-MiniLM-L6-v2",
        apiKey: "",
        cache: {
            enabled: true,
            maxItems: 20_000,
        },
    },
    llm: {
        provider: "",
        endpoint: "",
        model: "",
        temperature: 0,
        fallbackToHost: true,
        apiKey: "",
        timeoutMs: 45_000,
        maxRetries: 3,
    },
    skillEvolver: {
        // Empty by default — falls back to the shared `llm` settings.
        // Operators set this when they want a stronger model (e.g.
        // claude-sonnet / gpt-5-thinking) for skill crystallisation.
        provider: "",
        endpoint: "",
        model: "",
        apiKey: "",
        temperature: 0,
        timeoutMs: 60_000,
    },
    algorithm: {
        lightweightMemory: {
            enabled: true,
        },
        capture: {
            maxTextChars: 4_000,
            maxToolOutputChars: 2_000,
            embedTraces: true,
            alphaScoring: true,
            // OpenClaw's tool messages don't include explicit "reflection"
            // blocks; without synthesis the alpha scorer sees an empty
            // reflection and forces α = 0 (see `core/capture/alpha-scorer.ts`
            // line 97). That makes reflection-weighted backprop degenerate
            // into pure γ-discount and produces flat V distributions —
            // L2 association + skill crystallization both starve. Enable
            // synth by default so even turns without explicit reflections
            // still contribute useful α values.
            synthReflections: true,
            llmConcurrency: 4,
            // V7 §3.2 batched variant. With "auto" we issue a single LLM call
            // per episode for both reflection synth and α scoring as long as
            // the episode is short enough — this collapses 2N per-step calls
            // (N synth + N α) into 1 batched call. Long episodes (>12 steps)
            // automatically fall back to the per-step path so the prompt
            // never overflows the model's context window. R_human + backprop
            // remain task-end events handled by `core/reward`, unchanged.
            batchMode: "auto",
            batchThreshold: 12,
            // `reflectionContextMode` controls which extra prompt context blocks
            // topic-end reflection receives:
            //   - "none": no TASK CONTEXT and no DOWNSTREAM STEP PREVIEW
            //   - "task": inject TASK CONTEXT only
            //   - "downstream": inject DOWNSTREAM STEP PREVIEW only
            //   - "task_downstream": inject both blocks
            // `longEpisodeReflectMode` controls the fallback used when an episode is
            // too long for batch scoring:
            //   - "per_step_parallel": keep the current parallel per-step path. Each
            //     step is reflected independently, using only the context blocks
            //     enabled by `reflectionContextMode` that are available without
            //     downstream preview.
            //   - "per_step_downstream": still run per-step work in parallel, but
            //     prebuild a bounded DOWNSTREAM STEP PREVIEW for each step (step+1
            //     through step+N, capped by `downstreamStepCount`) and inject it when
            //     `reflectionContextMode` includes "downstream".
            reflectionContextMode: "task_downstream",
            longEpisodeReflectMode: "per_step_downstream",
            downstreamStepCount: 3,
            taskContextMaxChars: 800,
            downstreamContextMaxChars: 1_200,
            downstreamPerStepMaxChars: 400,
            synthOutcomeMaxChars: 600,
        },
        reward: {
            gamma: 0.9,
            tauSoftmax: 0.5,
            decayHalfLifeDays: 30,
            llmScoring: true,
            implicitThreshold: 0.2,
            // 10 minutes was too long for interactive chat — users moved on
            // to the next task before reward ever fired, so no R_human was
            // ever computed and V stayed 0 for every trace. 30 s gives the
            // user a short window to reply ("thanks", "no, try again") that
            // the scorer picks up as explicit feedback; when nothing
            // arrives, the implicit fallback fires promptly so downstream
            // L2/L3/Skill stages aren't starved of signal.
            feedbackWindowSec: 30,
            summaryMaxChars: 2_000,
            llmConcurrency: 2,
            // Default lowered 2→1 to support single-shot CLI patterns
            // (`hermes chat -q "..."`, `openclaw run --once`). With the old
            // floor every CLI single-query episode was abandoned with
            // "对话轮次不足", starving reward → L2 → Skill of any signal.
            // Multi-turn TUI flows still trigger reward as before because
            // they always satisfy the looser bound. Operators wanting the
            // strict pre-2026Q2 behaviour can set 2 in config.yaml.
            minExchangesForCompletion: 1,
            // Lowered 80→40 to match the relaxed exchanges floor. 40 chars
            // is "ok"/"thanks" + a real follow-up clause; below that we
            // still skip as a triviality gate.
            minContentCharsForCompletion: 40,
            toolHeavyRatio: 0.7,
            minAssistantCharsForToolHeavy: 80,
        },
        l2Induction: {
            minSimilarity: 0.65,
            candidateTtlDays: 30,
            minEpisodesForInduction: 1,
            // Lowered from 0.05 → 0.005. Reward backprop V values for typical
            // multi-step turns (5-15 steps) are clustered around 0.02-0.5 even
            // for successful episodes; the old 0.05 floor was throwing away
            // most of the signal before induction could see it. Negative-V
            // traces are still excluded (they'd never count as "with-set"
            // evidence anyway).
            minTraceValue: 0.005,
            useLlm: true,
            traceCharCap: 3_000,
            gainEmaAlpha: 0.4,
            archiveGain: -0.05,
        },
        l3Abstraction: {
            // Lowered from 3 → 2. The original threshold required THREE
            // distinct active policies in the same domain cluster before any
            // world model could form, which in real usage takes weeks to
            // accumulate even for a focused user. Two compatible active
            // policies is the smallest meaningful cluster.
            minPolicies: 1,
            // Lowered from 0.1 → 0.02. With the Bayesian-shrinkage gain
            // formula (see core/memory/l2/gain.ts), a genuinely useful policy
            // that fires on a single-success path now scores around 0.05-0.20
            // (proportional to V_with - 0.5). 0.02 is well below that floor
            // but still cleanly rejects net-neutral noise.
            minPolicyGain: 0.02,
            minPolicySupport: 1,
            // Lowered from 0.6 → 0.3 so the typical 2-3 active policies in
            // an early-life install can still cluster into a world model;
            // strict 0.6 starved L3 in real usage.
            clusterMinSimilarity: 0.3,
            policyCharCap: 800,
            traceCharCap: 500,
            traceEvidencePerPolicy: 1,
            useLlm: true,
            // Lowered from 1 → 0 so abstraction can run as soon as the
            // ingredients show up, not on a per-day cadence.
            cooldownDays: 0,
            confidenceDelta: 0.05,
            minConfidenceForRetrieval: 0.2,
        },
        skill: {
            // Lowered from 2 → 1: a single supporting episode is enough to
            // attempt skill crystallization. Quality is still gated by
            // minGain + candidate trials below.
            minSupport: 1,
            // Lowered from 0.1 → 0.02. Same rationale as l3.minPolicyGain:
            // the new shrinkage-anchored gain formula gives positive scores
            // proportional to V_with − 0.5, so 0.1 was unreachable for any
            // policy that didn't have an explicit failure-cohort contrast.
            // 0.02 is enough to filter neutral-noise policies while still
            // letting genuinely-useful patterns crystallize.
            minGain: 0.02,
            // Lowered from 5 → 1. Demanding multiple trials in `candidate`
            // before a skill can graduate meant skills rarely promoted in
            // real usage; 1 lets the candidate→active transition happen
            // immediately on first successful invocation.
            candidateTrials: 1,
            // Lowered from 6 hours → 0: no cooldown, skills can re-evolve
            // as soon as new evidence arrives.
            cooldownMs: 0,
            traceCharCap: 500,
            evidenceLimit: 6,
            useLlm: true,
            etaDelta: 0.1,
            archiveEta: 0.1,
            minEtaForRetrieval: 0.1,
        },
        feedback: {
            failureThreshold: 3,
            failureWindow: 5,
            valueDelta: 0.5,
            minLowValueThreshold: 0.01,
            useLlm: true,
            attachToPolicy: true,
            cooldownMs: 60_000,
            traceCharCap: 500,
            evidenceLimit: 4,
        },
        session: {
            followUpMode: "merge_follow_ups",
            mergeMaxGapMs: 2 * 60 * 60 * 1000,
        },
        retrieval: {
            tier1TopK: 3,
            tier2TopK: 5,
            tier3TopK: 2,
            candidatePoolFactor: 4,
            weightCosine: 0.6,
            weightPriority: 0.4,
            mmrLambda: 0.7,
            includeLowValue: false,
            rrfConstant: 60,
            minSkillEta: 0.1,
            // Lowered from 0.35 → 0.25 so partial-match traces still surface
            // for users with smaller corpora.
            minTraceSim: 0.25,
            episodeGoalMinSim: 0.45,
            tagFilter: "auto",
            keywordTopK: 20,
            // Lowered from 0.4 → 0.2 with the 2026 ranker overhaul: the new
            // base relevance already uses channel rank as a first-class
            // signal, so the old 0.4 floor was over-pruning keyword hits
            // with modest V·decay.
            relativeThresholdFloor: 0.2,
            skillEtaBlend: 0.15,
            smartSeed: true,
            smartSeedRatio: 0.7,
            multiChannelBypass: true,
            skillInjectionMode: "summary",
            skillSummaryChars: 200,
            llmFilterEnabled: true,
            // Tighter than the legacy default (5) so the LLM filter has a
            // small budget; combined with the richer prompt (v3) this keeps
            // packets concise without over-dropping.
            llmFilterMaxKeep: 4,
            // Set to 2: skip the LLM precision pass when there's only one
            // candidate (no point ranking a single item). Anything with 2+
            // candidates still goes through the filter to drop off-topic
            // hits before injection.
            llmFilterMinCandidates: 2,
            llmFilterCandidateBodyChars: 500,
        },
    },
    hub: {
        enabled: false,
        role: "client",
        port: 18912,
        address: "",
        teamName: "",
        teamToken: "",
        userToken: "",
        nickname: "",
    },
    telemetry: { enabled: true },
    logging: {
        level: "info",
        detailedView: false,
        console: { enabled: true, pretty: true, channels: ["*"] },
        file: {
            enabled: true,
            format: "json",
            rotate: { maxSizeMb: 50, maxFiles: 14, gzip: true },
            retentionDays: 30,
        },
        audit: {
            enabled: true,
            rotate: { monthly: true, gzip: true },
        },
        llmLog: { enabled: true, redactPrompts: false, redactCompletions: false },
        perfLog: { enabled: true, sampleRate: 1.0 },
        eventsLog: { enabled: true },
        redact: {
            extraKeys: ["api_key", "secret", "token", "password", "authorization"],
            extraPatterns: [],
        },
        channels: {},
    },
};
/**
 * Set of dotted-path field names whose values must never be sent to the
 * viewer or any non-localhost surface. Used by `server/routes/config.ts`.
 */
export const SECRET_FIELD_PATHS = Object.freeze([
    "embedding.apiKey",
    "llm.apiKey",
    "skillEvolver.apiKey",
    "hub.teamToken",
    "hub.userToken",
]);
//# sourceMappingURL=defaults.js.map