我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

caveman TypeScript SDK(@caveman-ai/sdk)实战解析:单文件零依赖客户端的追踪、工具搜索、压缩与跨语言一致性体系

caveman TypeScript SDK(@caveman-ai/sdk)实战解析:单文件零依赖客户端的追踪、工具搜索、压缩与跨语言一致性体系 caveman TypeScript SDKcaveman-ai/sdk实战解析单文件零依赖客户端的追踪、工具搜索、压缩与跨语言一致性体系【免费下载链接】caveman why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman项目地址: https://gitcode.com/GitHub_Trending/caveman1/caveman本文以packages/sdk/typescript/CLAUDE.md为核心骨架结合src/index.ts约 2400 行的单文件实现、测试套件与跨语言 parity 契约完整讲解caveman-ai/sdk的目录布局、全部关键 APICave 客户端、CaveTrace 追踪、BM25 工具搜索、compress、context pack、checkpoints、runtime policy、retry loop breaker、jobs 预留面、wire 约定与常见陷阱。读完你可以直接安装并使用该 SDK理解它与 Caveman 网关之间的字节级契约并知道每个诚实性设计byte-safe 直通、basis: inferred、跨语言 parity 门禁背后的源码依据。1. 包概览单文件、零运行时依赖、Node ≥ 22.13SDK 是一个导出为 ES module 的单文件包全部实现集中在 src/index.ts。从 package.json 可以确认其发布形态包名caveman-ai/sdk当前版本 1.0.0MIT 许可type: module入口为dist/index.js类型声明dist/index.d.ts零运行时依赖——devDependencies中只有typescript5.9.3sideEffects: falseengines要求Node.js ≥ 22.13依赖原生 fetch、AbortSignal、WebCrypto 的 Ed25519 验签等能力关键脚本buildtsc、test:typestsc --project tsconfig.test.json仅编译类型断言、test:nodenode --test tests/*.runtime.mjs运行时测试针对编译产物dist/。安装与最小用法来自 README.mdnpm install caveman-ai/sdkimport { Cave } from caveman-ai/sdk; const cave new Cave({ apiKey: process.env.CAVE_API_KEY!, baseURL: http://127.0.0.1:8787, agent: support-agent, }); const result await cave.compress(large payload); console.log(result.output, result.basis); // basis is inferred连接类调用需要 Caveman 网关的 key本地 Engine 压缩能力则走独立的 Caveman 运行时与账号体系解耦。2. 目录布局与测试双轨制CLAUDE.md 给出的 Layout 小节是理解本包的钥匙文件职责src/index.ts整个 SDK导出Cave、CaveTrace、CaveOptions、CaveTool、ToolSearchResult、CompressOptions、CompressResult及全部ContextPack*类型tests/tool-search.test.ts纯类型级断言由tsc --noEmit编译校验不执行tests/tool-search.runtime.mjs运行时测试node:test 全局 fetch mock从dist/导入tests/runtime-policy.runtime.mjs tests/runtime-policy.test.tsruntime-policy 客户端驱动 packages/sdk/parity/runtime-policy.fixtures.json 的每一节fetch wire、签名用例、全部assignment_vectors严格浮点相等、全部guard_cases共享算子真值表在 fixture 里而非测试文件里以及全部decision_cases。约定是遍历数组永远不硬编码数量tests/parity.runtime.mjs跨语言一致性套件驱动 packages/sdk/parity/fixtures.json与 sdk-python 共享。同一份 fixture、两种语言——任何一端 SDK 多一个字段、少一个字段都会让 CI 变红tests/trace-continuity.runtime.mjstrace/span id 铸造 哪些请求携带x-cave-trace-id/x-cave-parent-span-id镜像 Python 的tests/test_trace_continuity.pytsconfig.json / tsconfig.test.json两套配置测试配置额外覆盖tests/两者都继承仓库根的 tsconfig.base.json仓库实际测试目录还包含 assembly.runtime.mjs、cave-plan.runtime.mjs、context-pack.runtime.mjs、exporter.runtime.mjs、task-profile.runtime.mjs、tool-events.runtime.mjs、transport.runtime.mjs、packaging.runtime.mjs、shared-context.runtime.mjs、structural.runtime.mjs 等覆盖了后文各 API 面。核心约定Conventions 节必须原样保留测试双轨.test.ts只做类型断言只编译不运行.runtime.mjs是运行时测试对dist/运行。因此先构建再跑运行时测试pnpm build pnpm test:node。wire 方向请求体键名对网关一律snake_case响应映射为camelCase体现在ToolSearchResult上。x-cave-workflow头永不省略默认取defaultWorkflow ?? unlabeled-workflow。延迟工具搜索的会话交接三处联动请求体session_id、结果sessionId、provider 请求头x-cave-tool-session。任何改动必须同步更新 sdk-python 与 parity fixtures。3. Cave 客户端构造与配置new Cave(options)必填apiKey、baseURL、agent源码在 src/index.ts。完整CaveOptions类型L4比文档清单更细逐字段说明字段说明apiKey/baseURL/agent必填baseURL必须是无凭据、无 query/fragment 的绝对 http(s) URL尾部斜杠会被归一化defaultWorkflow工作流标签缺省时回落到CAVE_WORKFLOW环境变量再回落到unlabeled-workflowretentionmetadata \| zdr \| configuredverifyOnInit可选布尔controlURL保留给 control-api/api/v1/*面的独立地址同样经过严格 URL 校验user不透明的终端用户标识作为x-cave-user-hash转发它是原始值透传——若含 PII调用方须自行先哈希timeoutMs所有 SDK HTTP 请求的有限截止时间默认 30 秒必须是正安全整数signal调用方级取消信号应用于所有 SDK HTTP 请求从源码结构看一个有趣的细节构造函数通过globalThis读取CAVE_WORKFLOW而非process保持浏览器中立环境变量值会先小写化并按[a-z0-9_-]{1,96}校验非法值被忽略而不是让每个请求都 400——这让cave wrap --workflow x之类的包装器无需改代码即可给 SDK 应用的所有请求打标签且显式传入的defaultWorkflow永远优先。4. 追踪cave.trace 与 trace 连续性cave.trace(opts, fn)把回调包进一个CaveTraceid 铸造规则trace 用与 OTel exporter 相同的 RNG 铸造traceId32 位小写 hex与根spanId16 位小写 hex。续接入口 traceopts.traceId/opts.spanId用于续接入站 trace形状不是精确 hex 的值会被替换而不是上线源码中normalizeTraceId/normalizeSpanId保证。头注入的边界只有通过 trace 发出的 provider 调用和 trace 作用域内的/sdk/v1/*调用才携带x-cave-trace-idx-cave-parent-span-id直接挂在Cave上构建的 provider 客户端与 SDK 调用两者都不带。trace-continuity.runtime.mjs 专门验证这一点。工具调用 spantrace.tool(name, options, fn)在工具执行前后向POST /sdk/v1/events上报span_type: tool.call事件序列号、耗时、ok/error 结果该上报是尽力而为的元数据——telemetry 失败绝不能替换或吞掉工具的结果/错误源码 L807-L817 的.catch(() undefined)。CaveTrace.exporter({serviceName?})返回按服务名 memoized 的OTelExporter其defaultTraceId就是本 trace 的 id——SDK 自己录的 span 和网关的请求行因此并入同一条 trace。runtime-policy 的 decision span 若传入CaveTrace也复用同一个调用方可达的默认缓冲调用trace.exporter().flush()即可把它们发出去。此面镜像 Python 的Trace.exporter。5. 延迟工具搜索BM25/嵌入排序 会话交接这是 SDK 的核心省 token 面。两个入口共享同一契约cave.tools({ catalog, strategy })→ 返回{ initial, strategy, search(query, opts?) }。cave.toolSearch(catalog, query, opts?)→ 直接变体适合你在外部管理 catalog 的场景。关键行为文档 源码 toolSearch 实现 印证search()是异步的返回PromiseToolSearchResult——这是对 1.0 的破坏性变更旧版同步、返回CaveTool[]调用方必须await。opts.rankerbm25 | embeddings逐字透传给网关SDK 从不算相似度byte-safe、零依赖。网关只有在接入了嵌入 provider 时才认embeddings。opts.toolSessionId发送session_id让 provider 侧回调能把已被调用过的延迟工具重新注入。交接的完整链路是请求体session_id→ 结果sessionId→ provider 头x-cave-tool-session。strategy 语义源码 L461-L493all→initial即整个 catalogdeferred→initialalwaysLoad工具 至多initialToolCount个默认 8懒加载工具search()再按需从网关拉取。永不带search()调用就返回全量目录。另有maxLoadedTools上限校验必须 ≥ alwaysLoad 数量。结果映射响应体sent_schema_tokens/full_schema_tokens映射为sentSchemaTokens/fullSchemaTokenscamelCasesavedTokens是本地派生值full - sent不来自网关响应reductionPct四舍五入到一位小数Math.round(x * 1000) / 10。schema token 计数器是估算tokenBasis披露用的是什么计数器basis恒为inferred。防御性校验响应里的工具名必须在本地 catalog 中存在且不重复否则抛错——网关不能替你发明工具。ToolSearchResult的完整字段类型定义sessionId?、tools、sentSchemaTokens、fullSchemaTokens、deferredCount、method、tokenBasis、basis: inferred、只读的savedTokens与reductionPct。6. 压缩与上下文compress / context.pack / checkpoint6.1 cave.compress —— 唯一的变小字节路径且必须委托cave.compress(payload, opts?)→PromiseCompressResultPOST /sdk/v1/compress把 Engine 的报告映射出来。文档 Gotchas 强调的第一条就是byte-safeSDK 把请求体逐字发给网关不允许改写compress()是唯一能产出更小字节的路径而它委托给 Engine从不自己实现压缩器。失败语义compress 实现 逐条印证任何传输/解析问题非 2xx、响应缺output字符串、token 计数非法、tokensAfter tokensBefore一律fail-closed 直通output是原始输入、ratio: 0、无recoveryHandleratio不由服务端字段决定而是从校验过的两个计数器重新计算——重算而不是保留一个不一致或乐观的服务端字段tokenCountBasis披露 Engine 用的计数器如o200k_base或approx_chars_div_4basis恒为inferred——SDK 从不发verified成功时可选带出recoveryHandle恢复字节级原值的凭据、method如toon/elision、losslessToModel。CompressOptions.contentType支持json | toon | log | code | diff | search-result | text | toolschema等提示用于 Engine 的检测器。6.2 cave.context.pack —— 连接态、有损的选择器cave.context.pack(query, items, options)→PromiseContextPackResultconnected-onlyPOST /sdk/v1/context/pack。文档明确其定位它决定什么进入模型窗口而 cache-optimal assembly 决定被选内容放在哪——两者互补而非替代。要点它把条目字节发给网关从不在本地 wrap 运行是有损选择器绝不通 CCR/ledger返回精确的deferredIds请求 id 减去选中 id按请求顺序调用方必须保留这些被延迟的条目以便补充传输失败或报告畸形时返回全部原始条目且tokensSaved为 0零推断节省而不是谎称省了多少源码中的完整性校验相当严格contextPack 实现maxTokens必须为正、条目 id 不可重复、选中 id 必须属于请求集合、deferred_ids必须与期望集合逐项一致、tokensUsed tokensSaved tokensBefore、deferredCount deferredIds.length任一不满足即回落到 passthrough。ContextPackItem支持id/text/ 可选tokens/ RFC 3339timestamp/priority/pinpin为必需上下文钉住的条目放不下时调用返回诚实的 0ContextPackOptions有maxTokens必填 0、reserveTokens、now、recencyHalfLifeMs、recencyWeight、errorBoost。6.3 checkpoint 与 expand —— 可逆性是强制要求CaveTrace.context.checkpoint()POST /sdk/v1/checkpoints网关持久化Valkey并返回可逆的source_refCaveTrace.context.expand(sourceRef)GET 半程GET /sdk/v1/checkpoints/{ref}/expand返回存储的{source_ref, version, messages, checkpoint}。文档的说法很直白一个无法被 expand 的 checkpoint 就是 bug。同一 trace 下还有artifacts面CaveTrace.artifacts.page()发送版本化的{value, options, workflow}网关注入x-cave-artifact-envelope: value-v1头网关只存储 JSONvalue非 verbatim 策略存储成功后返回带artifact_id的占位包裹文本artifacts.get(id)执行鉴权取回strategy: verbatim完全绕过存储直接返回原值。7. Provider 客户端与其他 API 面7.1 薄 provider 客户端cave.openai()/cave.anthropic()/cave.gemini()/cave.vertex()都是经网关代理的薄客户端前缀分别为/openai/v1、/anthropic、/gemini、/vertex可选upstreamKeyVertex 场景是 Google OAuth2 访问令牌网关以Authorization: Bearer …转发每个客户端都暴露.rawfetch 逃生舱镜像 Python 的Provider.raw且 raw 请求被约束在本 provider 前缀内。cave.bedrock({ region, endpoint? })特殊它是一个零网络的第一方路由描述符——endpoint 缺省runtime时gatewayPrefix为/bedrock显式mantle时为/bedrock/anthropicsdkOnly: false镜像 Python 的sdk_only不含任何 AWS 秘密。7.2 其余关键 API文档 Key APIs 节逐条对应cave.prompts.internalBrevity({style, preserveErrorsVerbatim?, preserveCodeVerbatim?})输出风格片段style: none返回空串实现 L597-L600 就是一行三元表达式CaveTrace.model.openai.responses.create(body, {cave:{latencyClass, toolSessionId}})传latencyClass会设置x-cave-async头interactive之外均为true传toolSessionId会设置x-cave-tool-sessioncave.exporter({serviceName?})→OTelExporterrecordSpan(...)把当前 GenAI 字段映射为gen_ai.*export()以 OTLP/JSONPOST到标准/v1/traces头来自otlpHeaders()旧路径/otlp/v1/traces仅服务端兼容保留。SpanOptions支持inputTokens/outputTokens/cachedTokens/costUsd等 provider 报告值cave.cavePlan()GET /sdk/v1/cave-plan以项目 key 的plan:read作用域鉴权逐字返回 snake_case 计划——所有美元数字都是推断值且是每日费率SDK 从不重推或按月投影cave.sharedContext.put/get会话键化的多 agent 共享上下文POST/GET /sdk/v1/shared-context/{key}网关按租户命名空间隔离。7.3 retryLoopBreaker 与 jobs 预留面cave.retryLoopBreaker(threshold 3)→RetryLoopBreaker。.record(name, args)在连续第threshold 1次相同名称 稳定序列化参数签名工具调用时抛RetryLoopError.guard(name, args, fn)先 record 再执行fn任何不同调用都会重置连击计数.reset()可手动清零实现 L664-L709。cave.jobs是预留的JobsClient面submit/status/cancel/wait/submitAndWait每个方法都在网络 I/O 之前本地失败抛出code cave_async_jobs_unavailable的AsyncJobsUnavailableError——在持久加密请求存储、凭据托管与可排空 worker 就位之前不允许出现假的已排队/已完成。8. runtimePolicy签名校验、TOFU 与永不抛异常的路由决策cave.runtimePolicy({publicKey?, autoRefreshSeconds?, killEnv?})→RuntimePolicyClient是 SDK 中最重安全逻辑的一面实现文档每条断言都能在源码找到对应refresh()是唯一网络调用GET /sdk/v1/runtime-policy标准头减去content-type请求挂 30 秒AbortSignal镜像 Python 的timeout30。响应有界读取content-length超过 1 MiB 直接取消流式读取累计超 1 MiB 抛oversized_responsefetch 实现没有有界可读 body 时抛bounded_response_unavailablefail closed 而不是调用无界text()。Ed25519 验签在解析之前对bundle字符串的精确 UTF-8 字节验签WebCrypto RFC 8410 SPKI 前缀任何异常都是false。TOFU 钉住时机签名验证通过的那一刻就钉住公钥——早于 schema_version / sequence 检查。否则会出现降级窗口第一个签名 bundle 因 schema 被拒后一个无签名的 bundle 反而被接受verifyBundle 注释 L1222-L1266 把这段推理写得很完整。schema 与单调性只接受caveman.runtime-policy.v1sequence回退即拒runtime policy sequence regressed一切失败保留 last-known-good。autoRefresh 不堆叠后台 tick 落在一次进行中的 refresh 上时跳过而不是排队。decide(taskFamily, {unitKey, context, trace})同步、纯本地、永不抛内部故障降级为baselinekill()本地闩锁killEnv默认CAVEMAN_POLICY_KILL每次 decide 重读运行中可翻转state()给快照。实验语义holdout 先切出并强制落到 fallback抑制而非更危险的变体缺unitKey或实验配置非法时从不猜测 armno_unit_key/invalid_experiment同一 family 在获胜层级有 1 个候选时返回ambiguous_policy宁缺毋猜。确定性分桶导出的policyUnitFraction(...keys)是 Goshared/platform/sampling.Fraction的逐字节移植——每个 key 前缀 8 字节大端长度、SHA-256、取前 8 摘要字节做大端 uint64 右移 11 再除 2^53。导出它是为了让调用方能复现分派也让跨语言 fixture 能按位钉住这个移植。定位声明只做路由到处没有节省词汇no savings vocabularyverify/budget/escalation对 SDK 是黑盒原样透传给调用方。其测试 runtime-policy.runtime.mjs约 1176 行驱动共享 fixture runtime-policy.fixtures.json 的全部用例节是这一面不靠口头保证的落地方式。9. 跨语言 parity漂移即 CI 失败文档 Gotchas 中最硬的一条是mirror sdk-python每个字段/方法在两个 SDK 中都存在由共享 parity 套件强制——一次漂移是 CI 失败不是约定失误改了一个 SDK必须同时改另一个和 fixture。packages/sdk/parity/CLAUDE.md 进一步说明这份契约如何执行fixtures.json 是契约本体一个config、命名头集合std_headers/std_headers_traced/std_headers_async_traced/otlp_headers与有序operations列表每个 operation 带input、预制response或transport: error强制 byte-safe 直通和expect块wire 的 method/path/headers/body 或 body_keys resultTS 半边是 tests/parity.runtime.mjsmock fetchPython 半边是 sdk-python 的tests/test_parity.pymock urlopen每半边对每一个operation 都有 handler缺 handler 就是失败不是跳过编辑规则给一个 SDK 加字段 → 在这里加 operation → 另一个 SDK 的半边变红那个红色正是目的所在头按 key 小写化比较Python urllib 会大写化fixture 值必须避开两语言编码不一致的字符如! ( ) *JSencodeURIComponent与 Pythonquote分歧随机值不得进入断言SDK 本该铸造的 id 通过 operationinput注入并钉在期望头集合里。这就是 CLAUDE.md 所谓release gate, not documentation的含义它不是描述行为的文档而是行为本身的裁判。10. 陷阱清单与适用前提把文档 Gotchas 节整理成一张可操作清单byte-safe 是底线SDK 对网关的请求体逐字发送禁止改写唯一变小字节的路径是compress()且它委托 Engine任何异常直通原文。context packing 是 connected-only 且有意有损发送条目字节到网关、从不在本地 wrap 运行、依赖调用方保留deferredIds点名的每条它选什么进窗口cache-optimal assembly 管放哪里。mirror sdk-python单侧改动必须双侧 fixture 同步。npm 名称现状发布名caveman-ai/sdkworkspace 名在 npm 重定向方案落地前保持caveman-ai/sdk。deferred 初始集alwaysLoad工具 至多initialToolCount默认 8不带search()调用永不返回全量 catalog。数字语义reductionPct一位小数savedTokens是派生值full - sent不是网关字段SDK 全链路basis: inferredverified只属于 Cloudactive路径。适用前提Node ≥ 22.13、ES module 环境、连接类 API 需要网关 key运行测试需先pnpm build pnpm test:node。所有接口面provider 客户端、compress、延迟工具搜索、可逆 checkpoint 与 artifacts、retry-loop 中断、runtime policy、零依赖 OTLP/JSON exporter与 README.md 的清单一一对应异步作业则如前所述为本地失败的预留面。总结caveman-ai/sdk用约 2400 行单文件实现了一个网关协作型 TypeScript 客户端以Cave/CaveTrace两个入口覆盖追踪、工具延迟加载、压缩、上下文打包、checkpoint 与产物五大能力以 byte-safe 直通、inferred基线、确定性分桶移植和 Ed25519 TOFU 验签守住诚实性与安全性边界再以与 Python SDK 共享的 parity fixture 把两语言一个契约变成 CI 门禁。对需要把 agent 接入 Caveman 网关、同时要求可观测与可验证节省语义的 TypeScript 项目这套 API 与约定尤其x-cave-workflow永省略除、snake_case 出/camelCase 入的 wire 方向、以及三处联动的 tool-session 交接是完整的实现事实来源。【免费下载链接】caveman why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman项目地址: https://gitcode.com/GitHub_Trending/caveman1/caveman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表