<?xml version="1.0" encoding="UTF-8"?>
<!--
    大龙虾全局配置 / Big Lobster global tunables.
    =======================================================
    - cyan <config> 机制加载：<bean class="..." factory="instance"> 形式，
      factory="instance" 要求目标类 @Injectable(singleton=true) 并提供 public 空构造器；
      子标签名 = JavaBean setter 属性名（小驼峰）.
    - 不写的项使用 LobsterConfig 源码中的默认值，所以本文件只需覆盖要改的项即可.
-->
<config>

    <bean class="com.gzzm.lobster.config.LobsterConfig" factory="instance">
        <!-- Agent Runtime -->
        <maxTurnsPerRun>30</maxTurnsPerRun>
        <!-- 上下文预算兜底：实际预算 = max(此值, ModelProfile.contextWindow - maxOutputTokens - 2000).
             长窗口模型（Claude 200k / DeepSeek 128k 等）会自动用更大的动态值，无需在此调高. -->
        <defaultContextBudgetTokens>100000</defaultContextBudgetTokens>
        <llmTurnTimeoutMs>120000</llmTurnTimeoutMs>
        <perUserConcurrentRunLimit>3</perUserConcurrentRunLimit>
        <perThreadConcurrentRunLimit>1</perThreadConcurrentRunLimit>

        <!-- Context summarization：触发折叠时是否调主路由 LLM 做历史摘要（对齐 Claude Code auto-compact）.
             默认关闭，走 bullet 折叠（零成本）；开启后摘要失败会自动退回 bullet.
             幂等缓存：同一段历史（threadId + 内容 hash）只调一次 LLM，结果落 ContentStore +
             AI_COMPACTION_EVENT 表，后续命中直接复用——长对话成本可控. -->
        <summarizerEnabled>false</summarizerEnabled>
        <summarizerMaxInputChars>24000</summarizerMaxInputChars>
        <!-- Summarizer 专用模型；留空沿用主路由 primary（贵），配置便宜小模型推荐：
             AI_MODEL_PROFILE 表里挂一个 deepseek-v3-cheap / claude-haiku-4-5 之类 modelId. -->
        <!-- <summarizerModelId>claude-haiku-4-5</summarizerModelId> -->

        <!-- Memory -->
        <memoryMaxContentLen>500</memoryMaxContentLen>
        <memoryWriteLimitPerMin>20</memoryWriteLimitPerMin>

        <!-- Tool -->
        <toolRateLimitPerMin>60</toolRateLimitPerMin>

        <!-- List paging -->
        <listDefaultPageSize>20</listDefaultPageSize>
        <listMaxPageSize>200</listMaxPageSize>

        <!-- Admin -->
        <adminRoleName>ai_admin</adminRoleName>
        <apiKeyMaskTailLen>4</apiKeyMaskTailLen>

        <!-- ================= OA 知识库 (KB API v1) ================= -->
        <!-- 真实知识库服务的 endpoint base.
             nest.xml 默认绑定 OaKnowledgeClientHttpImpl，需要在此配置 base URL，
             否则启用了 KB 开关后第一次 search 调用会抛 kb.not_configured.
             路径契约：base + /scopes (GET) / /search (POST) / /detail (POST). -->
        <!-- <oaKnowledgeBaseUrl>http://oa.intranet.example.com/api/kb</oaKnowledgeBaseUrl> -->

        <oaKnowledgeBaseUrl>http://192.168.1.13:8900/api/v1/lobster-kb</oaKnowledgeBaseUrl>

        <!-- 入口鉴权 token（可选）—— 用户身份仍走 X-User-Id / X-Dept-Id / X-Org-Id header -->
        <oaKnowledgeApiKey>dev-lobster-kb-key</oaKnowledgeApiKey>
        <!-- forced 模式（用户在 UI 选「强制引用」）下注入的最大 KB 条目数 -->
        <kbForcedInjectMaxHits>10</kbForcedInjectMaxHits>

        <!-- LLM Trace：每次 LLM 完整请求+响应经 ContentStore 落盘，ref 存入 ModelCallLog.traceRef -->
        <llmTraceEnabled>true</llmTraceEnabled>
        <llmTraceMaxMessageChars>0</llmTraceMaxMessageChars>

        <!-- Storage: ContentStore 根 base；最终落盘路径为 <base>/files/lobster-content/...
             默认按 OS 自动选择：Linux → /home/app/lobster，Windows → d:/lobster.
             需要自定义时取消下面一行注释并改成目标目录. -->
        <!-- <contentStoreBase>/home/app/lobster</contentStoreBase> -->

        <!-- Upload：用户上传的文件走 USER_UPLOAD 通道，由 DocumentParser 解析为 markdown + outline -->
        <uploadMaxBytes>52428800</uploadMaxBytes>
        <uploadInlineMaxChars>4000</uploadInlineMaxChars>
        <parsedMarkdownMaxChars>80000</parsedMarkdownMaxChars>
        <xlsxInlineRowLimit>500</xlsxInlineRowLimit>
        <outlineFoldThreshold>500</outlineFoldThreshold>
        <pdfBookmarkMaxDepth>3</pdfBookmarkMaxDepth>

        <!-- ================= 沙箱 (code_exec) ================= -->
        <!-- 镜像与 docker CLI -->
        <sandboxImage>lobster-sandbox:py3.11-office-v4</sandboxImage>
        <!-- <sandboxDockerBin>docker</sandboxDockerBin> -->

        <!-- 资源上限 -->
        <sandboxDefaultTimeoutSec>30</sandboxDefaultTimeoutSec>
        <sandboxMaxTimeoutSec>120</sandboxMaxTimeoutSec>
        <sandboxMemoryMb>512</sandboxMemoryMb>
        <sandboxCpus>0.5</sandboxCpus>
        <sandboxPidsLimit>128</sandboxPidsLimit>
        <sandboxOutputMaxBytes>52428800</sandboxOutputMaxBytes>
        <sandboxCodeMaxBytes>65536</sandboxCodeMaxBytes>
        <sandboxRatePerMinute>10</sandboxRatePerMinute>

        <!-- 输入 staging 上限 -->
        <sandboxInputMaxBytes>20971520</sandboxInputMaxBytes>
        <sandboxInputTotalMaxBytes>104857600</sandboxInputTotalMaxBytes>
        <sandboxInputMaxFiles>20</sandboxInputMaxFiles>

        <!-- 目录（默认按 OS 自动选择，需要自定义时打开注释）-->
        <!-- <sandboxWorkDir>/srv/sandbox</sandboxWorkDir> -->
        <sandboxPoolEnabled>true</sandboxPoolEnabled>
        <sandboxPoolSize>2</sandboxPoolSize>
        <sandboxPoolRoot>/srv/sandbox/pool</sandboxPoolRoot>
        <!-- <sandboxBundleCacheDir>/var/cache/lobster/skill-bundles</sandboxBundleCacheDir> -->
        <sandboxBundleCacheMaxEntries>64</sandboxBundleCacheMaxEntries>
        <sandboxBundleCacheMaxBytes>2147483648</sandboxBundleCacheMaxBytes>

        <!-- 用户 -->
        <sandboxUid>10001</sandboxUid>

        <!-- 系统 skill 扫描根（相对路径按 webappRoot / catalina.base / cwd 依次尝试）-->
        <systemSandboxSkillDir>WEB-INF/lobster/deploy/skills</systemSandboxSkillDir>
        <systemGuidanceSkillDir>WEB-INF/lobster/skills</systemGuidanceSkillDir>

        <!-- 包白名单文件 -->
        <sandboxInstalledPackagesFile>WEB-INF/lobster/sandbox-installed-packages.json</sandboxInstalledPackagesFile>
        <sandboxRequireInstalledPackagesFile>true</sandboxRequireInstalledPackagesFile>
    </bean>

</config>
