TencentDB Agent Memory 被引用的 cost-guard 目录并不存在

2026-08-16

翻开 TencentDB-Agent-Memory 仓库里 MemoryProxy/ 这个模块的 tsconfig.jsoncompilerOptions.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;同仓主模块 MemoryCore2.0.0-beta.1。项目仍在 beta 阶段,下面提到的文件路径、字段名、默认值随时可能变,请以仓库最新内容为准。

这个名字被写在哪几处

@context-proxy/cost-guard 这个模块名,在快照里出现在这些地方:

位置写法
tsconfig.jsonpaths 别名,指向 ./packages/cost-guard/src/index.ts
vitest.config.ts:11resolve.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.tssrc/server.ts 也各自因为它而有专门的日志与分支,下面会讲到。我们核到的口径是:除 tsconfig.jsonvitest.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:49storage.backend 的代码默认值是 sqliteconfig.example.yaml:176storage.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-70DEFAULT_CONFIG 定义了整段 costGuardenabled: falsemarkerOptIn: falseagentProfile: "auto"options: {};解析函数 parseCostGuardsrc/config.ts:201-232src/server.ts 有四处直接读 config.costGuard.*:35:93:188:265)。

config.example.yaml 这份 648 行的示例配置里,没有 costGuard: 这个段costGuard 一共只出现 3 次,全在注释行(第 58、60、450 行)。同类的还有 workbuddyRequestRoutingsrc/config.ts:144,默认 enabled: true,是唯一一个默认为 true 的 routing 开关,示例配置里同样没有这一段)和 badcaseCollector——后者的处置写在 parseCostGuard 里:顶层的 yaml.badcaseCollector 会被折叠进 options,且「without being interpreted」(src/config.ts:196-199:214-216)。

parseCostGuard 只读四个通用字段——enabledmarkerOptInagentProfileanthropicUpstream,其余的键原样塞进 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_disabledsrc/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 相关的报错,可以按这几步确认,全都只是看文件,不需要启动任何服务:

  1. MemoryProxy/ 下看目录是否存在。我们在快照里核到的是 Linux / macOS 侧 ls packages 返回 No such file or directory;Windows PowerShell 侧对应的判定命令是 Test-Path .\packages,这条是通用 shell 用法,不是项目文档里给的命令。
  2. 比对两处别名是否都指向同一条路径:tsconfig.jsoncompilerOptions.paths,和 vitest.config.ts:11resolve.alias。两处写的都是 packages/cost-guard/src/index.ts
  3. 看你实际用的存储后端。config.yamlstorage.backend 不是 cos 时,src/storage/factory.ts:98-117 那条动态 import 不会执行;是 cos 时才会走到,并且 :123-149 那一支是硬失败。
  4. 看启动日志里有没有 src/index.ts:74 那条 note。
  5. /health。按 src/server.ts:84-104,返回体里有 costGuardstorage{enabled,requested,effective,degraded,lastError?} 这几项。顺便一提,这里的 version 是硬编码字符串 "0.2.0"src/server.ts:90),跟 package.json:30.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-355if (forwardTimeoutMs > 0) 包住超时;Anthropic 侧 src/anthropicHandler.ts:452:493 无此判断;src/codexHandler.ts:1150-1156src/workbuddyHandler.ts:673-679 用的是硬编码 5 分钟的 setTimeout,两个文件里 grep 不到 config.server.forwardTimeoutMs。这是另一条独立的线。

我们没有核实的部分

npm installnpm testtsc --noEmit、docker build,我们一个都没有跑过,也没有向这个服务发过一个请求。所以「缺 packages/cost-guard 时 typecheck 到底是什么结果」,本文没有验证,只记录了文件层面的事实:别名在、目录不在、三处源码把它当模块名、src/storage/factory.ts:93-96src/index.ts:74 写了缺失时的处置。

扩展本身做什么,我们同样看不到——宿主只暴露 enabled / markerOptIn / agentProfile / anthropicUpstream 四个字段,其余原样透传(src/config.ts:193-199)。除此之外无从核实,就到此为止。

延伸阅读


本文依据 TencentDB Agent Memory 官方仓库(github.com/TencentCloud/TencentDB-Agent-Memoryfeat/server_team 分支上的 README、INSTALL、CHANGELOG、ROADMAP 与四个模块的源码整理, 核对日 2026-08-16,对应仓库快照 97f9465。该仓库的默认分支即为 feat/server_team。 本文内容为仓库源码与文档口径,我们没有部署、也没有运行过该项目的任何一个模块, 因此不涉及运行效果、检索质量与性能的任何描述。 该项目主模块处于 beta 阶段、其余模块版本号仍为 0.1.0,参数与接口随版本变动,请以仓库最新内容为准。 该项目会采集并存储团队的对话、文档与代码,属于敏感数据,是否使用请结合自身合规要求评估。 安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。