TencentDB Agent Memory 被引用的 cost-guard 目录并不存在
翻开 TencentDB-Agent-Memory 仓库里 MemoryProxy/ 这个模块的 tsconfig.json,compilerOptions.paths 里只有一条别名:
"paths": {
"@context-proxy/cost-guard": ["./packages/cost-guard/src/index.ts"]
}
然后去同目录下 ls packages,得到的是 No such file or directory。这个模块的根目录下确实没有 packages/,也没有 docs/、没有 gateway/。
先把口径交代清楚:以下全部基于 2026-08-16 采集的仓库快照 97f9465,分支是 feat/server_team——这个仓库的默认分支就叫 feat/server_team,不是 main 也不是 master,所以你贴 raw 链接、或者按习惯去 main 上找文件,找到的东西可能不是这一份。MemoryProxy/package.json 里的包名是 context-proxy(目录名 MemoryProxy 和包名不是一回事),版本 0.1.0;同仓主模块 MemoryCore 是 2.0.0-beta.1。项目仍在 beta 阶段,下面提到的文件路径、字段名、默认值随时可能变,请以仓库最新内容为准。
这个名字被写在哪几处
@context-proxy/cost-guard 这个模块名,在快照里出现在这些地方:
| 位置 | 写法 |
|---|---|
tsconfig.json | paths 别名,指向 ./packages/cost-guard/src/index.ts |
vitest.config.ts:11 | resolve.alias 同名别名,指向同一路径 |
src/guard-adapter.ts:123 | 把 "@context-proxy/cost-guard" 作为模块名常量 |
src/request-prepare-adapter.ts:57 | 同样把它作为模块名常量 |
src/storage/factory.ts:102 | 动态 import("@context-proxy/cost-guard") |
除此之外,src/index.ts 与 src/server.ts 也各自因为它而有专门的日志与分支,下面会讲到。我们核到的口径是:除 tsconfig.json 与 vitest.config.ts 这两条别名之外,还有 6 个源文件引用它,而目录本身不存在。
src/guard-adapter.ts 的文件头自述是「minimal bridge between host project and @context-proxy/cost-guard」,并说明宿主里有两个 adapter 会 import 这个包,它自己负责其中的 routing 那一半(src/guard-adapter.ts:2-5)。也就是说,宿主侧留的是接口和开关,真正干活的那段代码在另一个包里,而那个包不在这份快照里。
代码自己写了「它不在也能往下走」
这不是一个被忘掉的引用,代码里有针对缺失的明确处置。
src/storage/factory.ts:93-96 的注释写明:cost-guard 不可用(开源用户没有这个 submodule)时静默跳过。initProxyStorage 里,只有当 backend === "cos" 才会去动态 import("@context-proxy/cost-guard") 取 openKernelStsCosBackend,import 失败只打一条 warn(src/storage/factory.ts:98-117)。启动日志里也有对应的 note,src/index.ts:74 那条的原文是 cost-guard submodule missing or shark unreachable — cos falling back。
换句话说,这条动态 import 的触发条件是写死的:只有 backend === "cos" 才会走到它。而 src/config.ts:49 里 storage.backend 的代码默认值是 sqlite,config.example.yaml:176 里 storage.enabled 还是 false——按这两个默认值,这条 import 不在路径上。至于线上真实生效的配置是什么,我们无从得知:config.yaml 被 .gitignore 排除,仓库里只有 config.example.yaml。
但 cos 后端这一支不降级
这里有一处口径要特别留意,因为它和上面那句「静默跳过」听起来像是矛盾的,其实说的是两件事。
getProxyStorage 里,backend === "cos" 分支一旦装配失败,就打 !!! FATAL !!! 日志并 throw,注释原文的意思是:一旦配了 cos,就不给降级链任何机会,绝不能悄悄退到 process-local 的 sqlite / fs / memory(src/storage/factory.ts:123-149)。非 cos 的后端才保留 sqlite → fs → memory 的降级链,降级时会打 !!! DEGRADED !!! 和 !!! MULTI-NODE HAZARD !!!(src/storage/factory.ts:152-181),最后兜底到 MemoryStorage(:183-190)。
围绕 cos 这一支,示例配置里还有两句要一并读:COS 只支持 kernel-sts 模式,注释写「正式环境禁止静态 AK/SK」,并写明「Shark 不可用时 COS 后端装配失败,进程不会降级启动」(config.example.yaml:208-213);src/storage/factory.ts:31 也标了「static AK/SK 已删除(正式环境禁止)」。也就是说,装配 cos 要同时满足扩展包在位和 shark 可达两件事,任一不成立都会落到上面那条硬失败分支。
而文档侧的说法不止一种:MemoryProxy/README.md:253 写的是降级链 cos → sqlite → fs → memory,任一后端 init 失败自动降级;config.example.yaml:149-150 也是同样的表述;而同一份示例配置的 config.example.yaml:213 又写「Shark 不可用时 COS 后端装配失败,进程不会降级启动」。三处位置摆在这里,差异只作陈述,以你实读的仓库代码为准。
顺带一提,/health 这条路由在 storage 已启用、requested === "cos" 而 effective !== requested 时,status 返回 "degraded" 且 HTTP 状态码是 503,注释说明目的是让 k8s 的 LB 把这个 pod 摘掉(src/server.ts:80-87、:103)。README 的端点表里只写了「runtime health check(includes storage.effective)」(MemoryProxy/README.md:198),示例响应给的是 degraded: false 的 200 情形(MemoryProxy/README.md:123-130),没有提这个 503。
costGuard 这段配置:代码读它,示例配置不给它
跟缺失目录连在一起的还有一段配置。src/config.ts:65-70 里 DEFAULT_CONFIG 定义了整段 costGuard:enabled: false、markerOptIn: false、agentProfile: "auto"、options: {};解析函数 parseCostGuard 在 src/config.ts:201-232。src/server.ts 有四处直接读 config.costGuard.*(:35、:93、:188、:265)。
而 config.example.yaml 这份 648 行的示例配置里,没有 costGuard: 这个段,costGuard 一共只出现 3 次,全在注释行(第 58、60、450 行)。同类的还有 workbuddyRequestRouting(src/config.ts:144,默认 enabled: true,是唯一一个默认为 true 的 routing 开关,示例配置里同样没有这一段)和 badcaseCollector——后者的处置写在 parseCostGuard 里:顶层的 yaml.badcaseCollector 会被折叠进 options,且「without being interpreted」(src/config.ts:196-199、:214-216)。
parseCostGuard 只读四个通用字段——enabled、markerOptIn、agentProfile、anthropicUpstream,其余的键原样塞进 options 交给扩展,注释原文是「every other key is kept opaque in options and handed to the extension untouched」(src/config.ts:193-199)。宿主侧对这些键不做解释,扩展本身又不在这份快照里,所以这些键该填什么、填了会怎样,我们无从核实,也不做推测。
路径里带 /cost-guard/ 时会撞到什么
即便扩展不在,URL 上那个 marker 的门控逻辑是完整在这份快照里的,值得单独看一眼,因为它决定了你请求打进去先撞到什么。
src/server.ts:35-50 注册了一道在所有业务路由之前的中间件:config.costGuard.markerOptIn 为 false 时,任何路径里含 /cost-guard/ 段的请求直接返 404,错误体是:
{
"error": "cost_guard_marker_disabled",
"message": "The /cost-guard URL marker is disabled on this deployment. Remove the /cost-guard segment from the path, or set costGuard.markerOptIn=true."
}
而这个开关的代码默认值就是 false(src/config.ts:65-70),示例配置里又没有可以打开它的段。同一位置还有一道对称的门控:injection.assetReflection.markerOptIn 为 false 时,含 /analyse/ 段的请求同样 404,错误码 analyse_marker_disabled(src/server.ts:60-76)。
marker 识别本身在 src/routes/whitelist.ts:198,正则原样是 /(?<=(?:\/[^/]+){2,})\/cost-guard(?=\/)/;注释解释了它为什么不会被 /cost-guarded/、/cost-guarding/、/pre-cost-guard/ 误触发,以及 spaceId 恰好叫 cost-guard 时不会误命中(src/routes/whitelist.ts:178-196)。路径规范化 normalizeWhitelistRequestPath 的五步顺序也写在注释里(:232-253):剥 query → 剥 /cost-guard marker → 剥 /analyse marker → 剥 /proxy/{spaceId} 前缀 → 剥 /{agent}/{spaceId} 前缀。
还有一处标注得很直白:src/server.ts:255-259 的注释写明 codex 侧「当前 codexHandler.ts 尚未接 resolveForwardTarget……cost-guard router 分流的实际支持独立 commit 处理」。这属于代码里自己标出来的未完成状态,照实记下。
你怎么判定自己撞的是这件事
如果你在这个模块上做二次开发、typecheck 或者跑测试时看到跟 @context-proxy/cost-guard 相关的报错,可以按这几步确认,全都只是看文件,不需要启动任何服务:
- 在
MemoryProxy/下看目录是否存在。我们在快照里核到的是 Linux / macOS 侧ls packages返回No such file or directory;Windows PowerShell 侧对应的判定命令是Test-Path .\packages,这条是通用 shell 用法,不是项目文档里给的命令。 - 比对两处别名是否都指向同一条路径:
tsconfig.json的compilerOptions.paths,和vitest.config.ts:11的resolve.alias。两处写的都是packages/cost-guard/src/index.ts。 - 看你实际用的存储后端。
config.yaml里storage.backend不是cos时,src/storage/factory.ts:98-117那条动态 import 不会执行;是cos时才会走到,并且:123-149那一支是硬失败。 - 看启动日志里有没有
src/index.ts:74那条 note。 - 看
/health。按src/server.ts:84-104,返回体里有costGuard与storage{enabled,requested,effective,degraded,lastError?}这几项。顺便一提,这里的version是硬编码字符串"0.2.0"(src/server.ts:90),跟package.json:3的0.1.0不是一个值,别拿它当版本依据。
什么情况说明不是这个原因
- 报错来自测试:这份快照里
find . -name "*.test.ts"的结果是 0,也没有任何__tests__目录,vitest.config.ts:7的四个 include glob 在快照里匹配到 0 个文件。README(MemoryProxy/README.md:318)说__tests__/分布在各子模块下。这是另一处文档与快照的差异,跟packages/cost-guard是两件事。 - 报错发生在请求路由阶段、返回的是 404 且错误码是
cost_guard_marker_disabled:那是markerOptIn开关的门控(src/server.ts:35-50),跟目录在不在没关系。 - 转发超时相关的问题也不在这条线上:OpenAI 侧
src/handler.ts:353-355用if (forwardTimeoutMs > 0)包住超时;Anthropic 侧src/anthropicHandler.ts:452、:493无此判断;src/codexHandler.ts:1150-1156与src/workbuddyHandler.ts:673-679用的是硬编码 5 分钟的setTimeout,两个文件里 grep 不到config.server.forwardTimeoutMs。这是另一条独立的线。
我们没有核实的部分
npm install、npm test、tsc --noEmit、docker build,我们一个都没有跑过,也没有向这个服务发过一个请求。所以「缺 packages/cost-guard 时 typecheck 到底是什么结果」,本文没有验证,只记录了文件层面的事实:别名在、目录不在、三处源码把它当模块名、src/storage/factory.ts:93-96 与 src/index.ts:74 写了缺失时的处置。
扩展本身做什么,我们同样看不到——宿主只暴露 enabled / markerOptIn / agentProfile / anthropicUpstream 四个字段,其余原样透传(src/config.ts:193-199)。除此之外无从核实,就到此为止。
延伸阅读
- 从头读起:TencentDB Agent Memory 是什么:团队级 Agent 记忆中枢怎么读
- 本专题共 40 篇,完整分组目录见专题页
- TencentDB Agent Memory 的 MemoryProxy 版本:0.1.0 还是 0.2.0
- TencentDB Agent Memory 的 MemoryProxy 配置:哪些字段真的会读
本文依据 TencentDB Agent Memory 官方仓库(github.com/TencentCloud/TencentDB-Agent-Memory)
feat/server_team 分支上的 README、INSTALL、CHANGELOG、ROADMAP 与四个模块的源码整理,
核对日 2026-08-16,对应仓库快照 97f9465。该仓库的默认分支即为 feat/server_team。
本文内容为仓库源码与文档口径,我们没有部署、也没有运行过该项目的任何一个模块,
因此不涉及运行效果、检索质量与性能的任何描述。
该项目主模块处于 beta 阶段、其余模块版本号仍为 0.1.0,参数与接口随版本变动,请以仓库最新内容为准。
该项目会采集并存储团队的对话、文档与代码,属于敏感数据,是否使用请结合自身合规要求评估。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。