ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Composio Examples Harness 实战指南:基于实时后端与调用轨迹的客户端一致性校验

Composio Examples Harness 实战指南:基于实时后端与调用轨迹的客户端一致性校验 Composio Examples Harness 实战指南基于实时后端与调用轨迹的客户端一致性校验【免费下载链接】composioComposio powers 1000 toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio导读harness/是 Composio 仓库中一套面向示例examples的回归校验工具链它把examples-manifest.json中登记的全部可运行入口entrypoint跑在一个实时 Composio 后端上逐条记录每个入口发出的每一次后端调用然后对同一组入口的两轮运行做逐调用call-for-call比对从而在升级客户端TypeScript / Python SDK前后量化验证行为没有发生变化。本文以 harness/README.md 为主线结合 harness/run.mjs、harness/parity.mjs、harness/backend-url.mjs、harness/trace/register.mjs、harness/trace-py/sitecustomize.py 与 scripts/examples-provision.mjs 的源码实现带你完整掌握如何选择后端、如何做一次客户端升级的前后一致性parity比对、如何安全地准备测试数据以及如何用自检命令验证 harness 本身是可信的。一、整体架构一次可复现的示例回归harness 的核心理念是把示例跑成可比较的信号源。整个体系由四个角色协作组件文件职责运行器 Runnerharness/run.mjs遍历examples-manifest.json中登记的入口逐个运行产出results.jsonl与每个入口独立的 trace 文件比较器 Comparatorharness/parity.mjs对两个运行目录做逐入口、逐调用比对输出 parity 报告追踪器 Tracerharness/trace/register.mjsTS/Node fetch、harness/trace-py/sitecustomize.pyPython httpx由运行器注入进程记录每个后端请求的(method, path-template)与状态分组数据准备 Provisionerscripts/examples-provision.mjs为 tier-2/3 入口准备 auth configs 与 connected accounts并以COMPOSIO_EXAMPLES_*环境变量形式输出1.1 入口清单manifest所有可运行入口登记在根目录的 examples-manifest.json 中目前共 92 个入口按 tier 分级tier 136 个无人值守只要进程以 0 退出即视为通过tier 234 个依赖 provisioner 预先准备好的认证状态auth configs / connected accountstier 313 个有界运行——输出命中 manifest 里登记的 readiness 正则即判通过并终止进程tier X9 个排除项不参与运行。每个入口声明了id、langts/py、pkgTS 包名、file入口文件、tier、运行所需的环境变量与ids来自 provisioner 的COMPOSIO_EXAMPLES_*导出、timeoutSec等字段。运行器在 loadManifest 中会先做字段完整性校验例如 tier-3 入口必须有readiness正则防止坏数据流入运行。1.2 运行产物一次 sweep 的全部产物落在.artifacts/examples-parity/run-id/目录下run-id 形如20260910-013000-xxxxxx-baselineresults.jsonl逐行记录每个入口的运行结果id、tier、statusgreen/red/skipped、exit、timedOut、readinessMatched、durationMs、traceFile相对路径等traces/entry-id.jsonl每个入口一份调用轨迹其中 entry-id 中的/会被替换为__见 runEntry/buildEnv 与 parity.mjs 的 tracePairssummary.json本轮总览runId、client、llm 模式、baseUrl、green/red/skipped 计数。二、后端选择COMPOSIO_BASE_URL的严格约束COMPOSIO_BASE_URL决定示例跑在哪个后端默认是 staginghttps://staging-backend.composio.dev。关键约束是只接受裸 https 根——携带路径、查询串、fragment 或内嵌凭据的 URL 一律拒绝。原因有二追踪器要把后端 host 钉死用于过滤记录provisioner 会在根上追加自己的 API 路径。校验逻辑见 harness/backend-url.mjsconst isBareHttpsRoot url.protocol https: url.pathname / !url.search !url.hash !url.username !url.password; if (!isBareHttpsRoot) { throw new Error(refusing malformed COMPOSIO_BASE_URL: ${value}); } return url.origin;Python 侧在 sitecustomize.py 中用urlsplit做了完全一致的结构检查不满足条件时直接os._exit(78)拒绝启动。.github/workflows/examples-live.yml中 CI 显式设置 staging因此默认值的变化不会影响 CI 行为。2.1 安全前提只跑在可丢弃的项目上把COMPOSIO_BASE_URL指向一个你愿意让示例触碰数据的项目。尤其注意scripts/examples-provision.mjs --gc会跨整个项目删除示例遗留的、超过 24 小时的资源——永远不要对一个你在意的项目运行它下文 §4.3 详解删除边界。此外出站邮件 denylist 由追踪器强制实施且不可按运行覆盖run.mjs在 buildEnv 中显式删除COMPOSIO_TOOL_DENYLIST环境变量而--llm mock会把模型流量拉到本地aimock服务器上保证没有任何 agent 能决定去写点什么。三、追踪器如何把行为变成可比较的信号parity 比较的对象是追踪器记录的(method, path-template)对。两条追踪器都由运行器注入示例代码本身从不引用COMPOSIO_TRACE_FILElint 强制3.1 Node/TS 侧fetch 包装harness/trace/register.mjs 通过NODE_OPTIONS--import注入见 buildEnv替换全局fetchID 归一化路径段若匹配ID_SEG如ca_、ac_、ti_、tr_、sess_前缀、UUID、纯数字等会被模板化为{id}使两次运行中不同的资源 ID 不影响比对状态分组响应状态码折叠为2xx/3xx/4xx/5xx网络异常记为ERR出站邮件防护命中默认 denylistGMAIL_SEND|GMAIL_REPLY|SEND_EMAIL|SEND_DRAFT|OUTLOOK[A-Z_]*SEND的后端工具执行在传输层直接抛错并记录s:BLOCKED绝不转发给后端LLM 流量对 openai/anthropic/generativelanguage 三个 host 只记{llm: hostname}标记不记路径。3.2 Python 侧httpx 钩子harness/trace-py/sitecustomize.py 通过PYTHONPATH的sitecustomize钩子加载见 buildEnv猴子补丁httpx.Client.send与httpx.AsyncClient.send同步实现模板化、状态分组、denylist 防护与 LLM 标记。整个追踪逻辑包在try/except里——追踪绝不允许拖垮示例本身。3.3 trace 的判定意义追踪记录被 parity.mjs 直接消费也在 sweep 中用来判定出站邮件防护是否被触发只要 trace 中出现s:BLOCKED该入口无论退出码如何都判红runPool 中的 blocked 检查——因为捕获到拒绝然后继续执行不能被算作有效覆盖。四、一次完整的客户端升级比对parity runparity run 对同一组 entry id 做两轮 sweep变更前后各一轮再按 trace 中的(method, path-template)对逐调用比较。4.1 标准流程# 1. 为你要 sweep 的项目准备 idcapture 之后立即 eval—— # 一次失败的 provision 运行绝不能被静默吞掉 out$(node scripts/examples-provision.mjs) eval $out # 2. 基线使用基线分支 checkout 上的钉死客户端 node harness/run.mjs sweep --client baseline --lang py --llm mock --ids $IDS # 3. 候选换入候选客户端后跑同一组入口 COMPOSIO_CLIENT_WHEEL/abs/path/composio_client-version-py3-none-any.whl \ node harness/run.mjs sweep --client candidate --lang py --llm mock --ids $IDS # 4. 比对两个运行目录 node harness/parity.mjs baseline-run-dir candidate-run-dir务必显式传--ids而不要依赖默认选择这样即使两个 checkout 对 manifest 的认知不一致两边也跑完全相同的集合。4.2 候选客户端来自本地产物而非版本声明COMPOSIO_CLIENT_TARBALLTypeScript与COMPOSIO_CLIENT_WHEELPython指向本地构建产物。Python wheel 用如下命令获取pip download composio-clientversion --no-deps两个 swap 都有保护性设计见 run.mjs 的 candidate 逻辑守卫如果项目实际解析到的客户端版本没变sweep 直接中止TS 侧校验解析出的composio/client版本Python 侧通过importlib.metadata.version(composio-client)校验自动恢复sweep 结束后被改动的文件pnpm-workspace.yaml、pnpm-lock.yaml、python/pyproject.toml、uv.lock都会恢复为运行前的快照snapshotTsBaseline/snapshotPyBaselinerestore*。Python 侧还有一个细节候选 sweep 期间运行器会临时去掉python/pyproject.toml里精确的composio-client钉版relaxPyClientPin。原因是多个入口通过pyWith安装本地./python项目而 uv 无法同时满足钉版 候选 wheel——不去掉钉版这些入口会因打包解析失败而静默变红悄悄缩小比较范围。4.3 数据准备与清理provisionerscripts/examples-provision.mjs 是一个幂等的预置检查为 tier-2/3 入口验证/创建examples-slug命名的 auth configsOAuth 类用use_composio_managed_authserpapi 这类 API-key 工具用use_custom_auth其存储值是刻意伪造的占位符而非真实密钥以COMPOSIO_EXAMPLES_*导出stdout 设计为可被eval所有值做了 shell 单引号转义缺失的 OAuth 连接可用--initiate-missing生成浏览器授权 URL--gc可加--dry-run预览是破坏性命令只删除示例自己创建的资源——从未变 ACTIVE 的 connected accounts、超额的 serpapi demo 账户、以及匹配examples-label-unix-seconds命名的 MCP configs。删除以auth config 名为examples-slug作为所有权标记isExampleOwned且只处理创建超过 24h 的资源保证并发运行安全项目里用户自己的配置永远不会被误删。值得注意的安全细节provisioner 的所有 API 调用带redirect: errorapi 函数防止 3xx 重定向把x-api-key转发给其他 host。4.4 读懂 parity 报告parity.mjs 的判定规则是只比较两边都 green 的入口任一侧 red、skipped 或缺失该入口记parity: false并附原因而不会让比较器直接失败。对两边都 green 的入口比较(method, path-template)集合是否相等忽略 parity-variance.json 中登记的允许差异对当前该文件为空列表{entries: []}。因此阅读报告时同时看compared与parityGreencompared是参与比较的入口数parityGreen是真正一致的数量检查 trace 是否非空两轮空 trace 的 parity 是空洞地成立的vacuous truth必须结合compared一起判断退出码语义report.length 0 report.every(r r.parity)时退出 0否则退出 1见 parity.mjs 末尾。五、验证 harness 自身selftest 与 neg5.1selftest验证 harness 本身的正确性node harness/run.mjs selftestcmdSelftest 覆盖的检查点包括后端 URL 处理staging 是默认值、裸 https 根被采纳、携带 path/query/凭据/明文 http 的 URL 被拒绝候选 swap 守卫TS/Python 的候选替换保护逻辑含已解除钉版的工程再解除会报错的负例已知好/坏 fixturests/anthropic/index这类已知好入口实际 selftest 用 error-handling-demo 入口必须退出 0harness/fixtures/always-fails.ts 与harness/fixtures/always_fails.py必须退出非 0两个追踪器harness/fixtures/trace-check.ts 与 harness/fixtures/trace_check.py 各发一个未认证请求验证 fetch/httpx shim 都记录了非 2xx 的 composio 行如GET /api/v3/toolkits比较器自身的接受/拒绝行为两个相同运行目录应通过候选侧缺失入口时比较器应拒绝。5.2neg对示例的互补检查node harness/run.mjs negneg用垃圾凭据nc-invalid前缀的假 key重跑示例期望每个入口都变红。任何在垃圾凭据下仍 green 的入口都被视为吞掉了错误error swallowing会以NEGATIVE-CONTROL FAILURES列出并使进程退出 1见 cmdNeg——这样的入口不能算作有效覆盖。可用--sample N --seed S做确定性抽样使用 mulberry32 伪随机数发生器种子可复现。六、运行模式与常用参数速查node harness/run.mjs sweep|neg|selftest [options]退出码语义0全部通过1存在发现红项/失败预期2用法或环境错误。参数适用命令说明--client baseline\|candidatesweep本轮身份默认baseline--lang ts\|pysweep / neg只跑某语言入口--ids a,bsweep / neg显式指定入口集合parity run 强烈建议--tiers 1,2,3sweep按 tier 过滤默认1,2,3--llm live\|mocksweep默认livemock时模型流量走本地 aimock默认127.0.0.1:4010可用AIMOCK_PORT覆盖provider key 被强制改写保证 mock sweep 不消耗 token--concurrency Nsweep / neg并行度默认 4neg 默认 6--sample N --seed Sneg确定性抽样COMPOSIO_BASE_URL全部后端根默认 staging只接受裸 https 根COMPOSIO_CLIENT_TARBALL/COMPOSIO_CLIENT_WHEELsweep(candidate)本地候选客户端产物COMPOSIO_TRACE_FILE内部追踪输出文件由运行器注入示例不得引用两个运行器细节值得注意并发与串行manifest 中标记serial的入口如触发器等有状态示例会排到并行池之后单独执行runPoolLLM mock 兼容性manifest 中llmMock: false的入口在 mock 模式下会被跳过记llm-mock-unsupported它们是仅限 live 的 canary。七、与 CI 的衔接.github/workflows/examples-live.yml把上述能力接入了 CI工作流支持client/lang输入对应 baseline/candidate 与 ts/py显式设置 staging 后端校验COMPOSIO_API_KEY存在产物.artifacts/examples-parity/作为examples-live-resultsartifact 保留 14 天。也就是说一次客户端发版可以完全自动化地完成基线 sweep → 候选 sweep → parity 比对任何未预期的调用集变化都会在合并前暴露。八、实践要点与边界提醒永远用专用项目跑sweep 会让示例真实调用后端、创建连接与 MCP 配置--gc会删项目里超过 24h 的示例资源。请只对可丢弃的项目运行。parity 不等于全绿两个 trace 都为空时 parity 空洞成立。阅读报告务必同时核对compared、parityGreen与 trace 非空。不要吞 provision 失败out$(node scripts/examples-provision.mjs) eval $out中eval报告的是被求值文本的退出状态必须用链式保证 provision 失败即终止。候选产物守卫是特性如果客户端解析版本没有实际变化sweep 会拒绝启动——这正是比较必须真实发生的保障。负例控制不可省neg是判定示例真的在调用后端的最低成本手段与selftest互为表里共同保证 harness 自身与示例两端的信号都可信。【免费下载链接】composioComposio powers 1000 toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表