@code-yeongyu/senpi-telemetry

中文文档
2026.11.9-2发布于 2026/11/09MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 7.6万

与供应商无关的遥测合同和用于pi的类型模式实用程序

中文使用文档
文档目录19 节
  1. 目录
  2. 安装
  3. 遥测概念
  4. 核心内容 API
  5. 适配器合同
  6. 无上下文
  7. 记忆参考适应器
  8. 适配器
  9. 已键入Schemas
  10. 开始和完成属性
  11. Schema 元数据
  12. Pi 软件包集成
  13. 安全和可移动性
  14. API 参考
  15. 核心类型和价值
  16. 方案定义和推论
  17. 测试子路径
  18. 发展
  19. 许可证

@earendil-works/pi-遥测

供应商中性遥测合同和Pi包的打字系统.

本套件提供:

  • 一个明确的、基于召回的 TelemetryContext 编号 : TelemetrySpan 合同;
  • a 共用资源 NOOP_TELEMETRY_CONTEXT· ;
  • 参考文献 InMemoryTelemetryContext 执行;
  • 带有推断出类型Script的序列式计划定义;
  • 没有导出者、全局电流平流状态或依赖遥测后端.

应用程序可以使用内存参考,或者为OpenTeleometter,哨兵,日志或另一个后端提供适配器. Pi包明确通过遥测上下文,并分别定义了它们的域计划.

目录

安装

npm install @earendil-works/pi-telemetry

# Bun alternative
bun add @earendil-works/pi-telemetry

遥测概念

遥测描述一个程序在运行时所做的. 使用跨度、属性、事件、状态和明确上下文的软件包模型:

概念普通语的含义
宽度一个操作的定时记录,例如加载账户或提出AI请求. 它开始于工作前,结束于工作完成后.
父母和子女的跨度操作可以包含较小的操作. 请求周期可能包含缓存查询和数据库查询。 他们一起组成一棵树,显示时间的花在什么地方.
属性某个跨度上附有一个点名的事实,例如: provider: "openai", (中文(简体) ), cache.hit: true,或 item_count: 12属性描述操作及其结果.
活动在一个期间某个点的命名事件,例如 retry.scheduled 或者说 cache.lookup. 活动没有持续时间,可能具有自己的属性.
状态手术结果: ok 或者说 error。错误状态可能包括错误名称和消息.
A. 背景情况指向横跨树上新工作所在的手柄。 从上下文开始的一段时期使它成为上下文的孩子.

例如,加载一个账户可以产生这种遥测:

example.account.load                         span
├─ attributes: account.id=123, found=true   facts about the span
├─ event: example.cache.lookup              occurrence during the span
│  └─ attribute: cache.hit=false            fact about the event
└─ status: ok                               final outcome

一个跨度是诊断数据,而不是商业状态. 记录它不得改变账户载荷的运行、成功、失败或持续。 一个适配器将这些通用概念翻译为OpenTeleometry,哨兵,logs或另一个后端使用的相应概念.

核心内容 API

A 类 TelemetryContext 开始一个跨度 围绕召回。 回调收到一个 TelemetrySpan,这也是孩子跨度的明确的父母背景.

import {
  NOOP_TELEMETRY_CONTEXT,
  type TelemetryContext,
} from '@earendil-works/pi-telemetry';

async function loadAccount(
  accountId: string,
  telemetryContext: TelemetryContext = NOOP_TELEMETRY_CONTEXT,
) {
  return telemetryContext.startSpan(
    {
      name: 'example.account.load',
      attributes: { 'example.account.id': accountId },
    },
    async (span) => {
      const account = await readAccount(accountId);
      span.setAttributes({ 'example.account.found': account !== undefined });
      return account;
    },
  );
}

将回调跨度传递给较低级别的工作,以创建清晰的筑巢:

return telemetryContext.startSpan({ name: 'example.parent' }, async (parentSpan) => {
  return parentSpan.startSpan({ name: 'example.child' }, async (childSpan) => {
    childSpan.addEvent('example.cache.lookup', { 'example.cache.hit': true });
    return performWork();
  });
});

没有公众 end() 方法. startSpan() 拥有和解并保持跨度,直到召回值或承诺达成为止。 对于以正常返回值为代表的预期失败,明确规定状态:

return telemetryContext.startSpan({ name: 'example.save' }, async (span) => {
  const result = await save();
  if (!result.ok) {
    span.setStatus({
      status: 'error',
      error: { name: 'SaveError', message: result.reason },
    });
  }
  return result;
});

适配器合同

适配器执行器 TelemetryContext 将通用API连接到它的后端。 它必须:

  • 创建一个孩子的跨度,并同步引用回调,准确一次;
  • 保存回调的返回值和拒绝值,在同步抛出后返回一个以同样值拒绝的承诺;
  • 保持土生土长,直到返回的诺言达成为止;
  • 将正常补全作为 ok 并投掷/拒绝为错误,除非设定了明确的状态;
  • 重复一个 setStatus() 要求最后写成;
  • 合并 setAttributes() ,后定义的值取代先前的值 undefined 忽略;
  • 使录制方法同步、被动和非抛出;
  • 无视定居后发出的呼吁;
  • 忽略一个失败的录制调用 解析 , 压制后端失败, 并且仍然执行商业回调一次 .

适配器可以在内部激活后端-内在环境上下文,用于自动仪表,但pi代码总是通过 TelemetryContext 参数。 导出器缓冲,冲出,采样,后端ID,后端特定上下文对象属于适配器. 使用 适配器套装 检查这些可见的语义.

无上下文

使用 NOOP_TELEMETRY_CONTEXT 当遥测为可选时:

import { NOOP_TELEMETRY_CONTEXT } from '@earendil-works/pi-telemetry';

const result = await NOOP_TELEMETRY_CONTEXT.startSpan(
  { name: 'example.operation' },
  () => runOperation(),
);

无上下文 :

  • 同步引用回调;
  • 保存返回的值和同步拒绝,并将同步丢入以相同值拒绝的承诺;
  • 使用一个共享的冷冻惰性跨度,包括嵌入式跨度;
  • 不检查或保留姓名、属性、事件或状态.

记忆参考适应器

InMemoryTelemetryContext 是后端中性引用执行。 用于测试、本地诊断和应用,如果有意想要在没有出口者的情况下进行本地过程捕获:

import { InMemoryTelemetryContext } from '@earendil-works/pi-telemetry';

const telemetry = new InMemoryTelemetryContext();

await telemetry.startSpan(
  { name: 'example.operation', attributes: { input: 'demo' } },
  async (span) => {
    span.addEvent('example.started');
    span.setAttributes({ output_count: 3 });
  },
);

console.log(telemetry.getSpans());

getSpans() 返回跨度启动顺序的已解开快照。 每个 RecordedTelemetrySpan 包含一个决定性的数字 ID, 父ID, 合并属性, 命令事件, 最终状态, 和解状态, 以及决定性的结束序列 。 它没有记录时间戳.

适配器可以正常使用 TelemetryContext,但存储是无约束的,并进行本地处理。 创建一个新实例来隔离测试或记录范围,除非呼叫者的数据政策允许,否则不捕捉敏感属性.

适配器

@earendil-works/pi-telemetry/testing 输出一个按组装型号排列的、独立运行的套装。 固定提供了新的上下文,并将其后端的完成跨度转换为正常 RecordedTelemetrySpan 快照 :

import {
  createTelemetryAdapterConformance,
  type TelemetryAdapterFixture,
} from '@earendil-works/pi-telemetry/testing';
import { describe, it } from 'vitest';

const conformance = createTelemetryAdapterConformance(async () => {
  const adapter = createMyTelemetryAdapter();
  return {
    context: adapter.context,
    getSpans: async () => adapter.normalizedSpans(),
    async [Symbol.asyncDispose]() {
      await adapter.close();
    },
  } satisfies TelemetryAdapterFixture;
});

for (const group of new Set(conformance.map((testCase) => testCase.group))) {
  describe(group, () => {
    for (const testCase of conformance.filter((candidate) => candidate.group === group)) {
      it(testCase.name, () => testCase.run());
    }
  });
}

套房检查同步的单一收录,结果和拒绝身份,自动和明确状态,属性合并,事件顺序,定居后惰性呼叫,筑巢并同时进行亲和,并抑制无法读取的遥测有效载荷故障. getSpans() 可能会在返回前冲出同步导出者。 测试子路径使用Node的断言 API;根遥测包保持运行时中立.

已键入Schemas

低等跨度 API 有意接受开放名称和属性包,因此适配器仍然通用. 域包可以定义封闭的,可序列化的策略并推断出它们中的确切类型TypeScript.

import {
  createTypedSpanStarter,
  defineTelemetrySchema,
} from '@earendil-works/pi-telemetry';

export const EXAMPLE_TELEMETRY_SCHEMA = defineTelemetrySchema({
  version: 1,
  spans: {
    'example.read': {
      description: 'Read one resource',
      parents: { kind: 'any' },
      startAttributes: {
        'example.resource': {
          type: 'string',
          required: true,
          values: ['account', 'project'],
          description: 'Resource kind',
        },
      },
      endAttributes: {
        'example.item_count': {
          type: 'number',
          description: 'Number of returned items',
        },
      },
      events: {
        'example.cache': {
          description: 'Cache lookup result',
          attributes: {
            'example.cache.hit': {
              type: 'boolean',
              required: true,
              description: 'Whether the cache contained the resource',
            },
          },
        },
      },
      status: {
        default: 'ok',
        errorWhen: 'The read throws or returns an error result',
      },
    },
  },
} as const);

const startSpan = createTypedSpanStarter(
  telemetryContext,
  [EXAMPLE_TELEMETRY_SCHEMA],
);

起步器每个跨度暴露出一个超载,并在编译时检查名称和属性. 在呼叫前必须缩小联盟值名称,保留每个运行时名称与其属性计划之间的关系. 它的回调接收到一个孩子的启动器 通过相同的计划, 已经捆绑在回调范围:

await startSpan(
  'example.read',
  { 'example.resource': 'account' },
  async (span, startChildSpan) => {
    span.addEvent('example.cache', { 'example.cache.hit': true });
    const accounts = await readAccounts();
    span.setAttributes({ 'example.item_count': accounts.length });

    await startChildSpan(
      'example.read',
      { 'example.resource': 'project' },
      async (childSpan) => {
        const projects = await readProjects();
        childSpan.setAttributes({ 'example.item_count': projects.length });
      },
    );

    return accounts;
  },
);

开始和完成属性

startAttributes 财务报告和审定财务报表 endAttributes 描述一个属性通常已知时,而不是单独的运行时存储 :

Schema 字段如何记录数值需求
startAttributes在输入的启动器中通过 attributes 创建时的参数每个定义都明确规定 required: true 或者说 false
endAttributes后通过"计划范围"填充 setAttributes() 方法总是可选

两套都在同一后端间距上成为了普通属性. 没有单独的终端属性有效载荷或终端回调。 在上述例子中, example.resource 何时知道 example.read 启动时 example.item_count 只在 readAccounts() 返回 :

await startSpan(
  'example.read',
  { 'example.resource': 'account' }, // required start attribute
  async (span) => {
    const accounts = await readAccounts();
    span.setAttributes({
      'example.item_count': accounts.length, // optional completion attribute
    });
    return accounts;
  },
); // resolving the callback settles the span

“结束”是指完成浓缩:在召回有效时,可以在任何时间设定最终属性,在无法使用时可以省略。 通话 setAttributes() 0倍有效。 这关系到早期的失败,取消,以及可能不存在于每个路径的特定提供者的数据.

重复 setAttributes() 调用合并到同一属性包。 后来定义的值取代了同一密钥的较早值,同时 undefined 被忽略。 计程镜法只接受当前跨度所声明的结束属性.

属性不会结束长度 。 返回、解决、投掷或拒绝回调控制结算; startSpan() 进行实际的终端操作。 在和解后拨打的适配电话是无效的.

启动器可以编写多个独立版本的策略:

import { AGENT_TELEMETRY_SCHEMAS } from '@earendil-works/pi-agent-core';

const startAgentSpan = createTypedSpanStarter(
  telemetryContext,
  AGENT_TELEMETRY_SCHEMAS,
);

Inline schema 阵列自动保留其tuple类型. 单独宣布的数组应使用 as const。整个阵列的字面上重复名称在编译时被拒绝;计划不合并、检查,也不在运行时保留.

Schema-衍生类型拒绝缺少所需的属性,未知的密钥,无效的闭合集值,未宣布的事件,以及空子计划中的属性. 尾端属性总是可选的浓缩;类型系统不需要 setAttributes() 被调用.

defineTelemetrySchema() 是输入的身份函数。 它返回了普通的JSON-序列相上的数据,并且不执行运行时验证或执行父规则.

Schema 元数据

支持的属性类型有:

  • string, (中文(简体) ), number,以及 boolean· ;
  • string[], (中文(简体) ), number[],以及 boolean[]。 。 。 .

属性定义支持 :

  • values: 已关闭的平面值集;
  • elementValues: 阵列元素的封闭集;
  • examples: 文献实例;
  • sensitive需要特殊处理的数据标记;
  • cardinality: 需要记录 low 或者说 high 至高无上.

开始和事件属性声明 required。结尾属性不;见 开始和完成属性。 。 。 .

父元数据是描述性计划数据 :

  • { kind: 'any' }: 根或任何调用器;
  • { kind: 'root_or_external' }: 根或计程器以外的调用器;
  • { kind: 'spans', spans: [...] }:只有所列计划跨度.

适配器不需要理解计划对象. 仪器辅助和测试人员利用它们保持所排放的名称和属性的一致性.

Pi 软件包集成

包的所有权被故意分割:

  • @earendil-works/pi-telemetry 拥有供应商中立合同、不公开和模拟参考背景、计划公用事业和适配器兼容套件;
  • @earendil-works/pi-ai 接受和宣传 telemetryContext 在提供者请求选项中,但没有遥测计划;
  • @earendil-works/pi-agent-core 拥有并输出 Pi AI 请求和驾驭 schemas, 它们的组合只读 schema tuple, 和打出跨度帮助器.
import {
  AGENT_TELEMETRY_SCHEMAS,
  AI_TELEMETRY_SCHEMA,
  HARNESS_TELEMETRY_SCHEMA,
  startAiSpan,
  startHarnessSpan,
} from '@earendil-works/pi-agent-core';

皮子计划是用皮子的 pi.ai.*, (中文(简体) ), pi.harness.*,以及 pi.session.* 名称。 适配器可以将其翻译为后端常规而无需更改所排放的pi词汇.

安全和可移动性

遥测是过程局部诊断,不是持久应用状态. 不坚持 TelemetryContext, (中文(简体) ), TelemetrySpan,或记录、信件、快照或被推迟的手柄中的后端-内存跟踪对象.

属性值被故意限制在原始的分级和数组. 域仪器应避免提示、补全、工具参数或输出、文件内容、供应商有效载荷、信头、证书和自由形式的出错细节,除非其计划和数据政策明确允许.

软件包不使用 AsyncLocalStorage 或其它运行时间特定环境上下文 API。 它适合Node.js, Bun,浏览器,以及工人;后端适配器仍然负责自己的运行时间相容性.

API 参考

核心类型和价值

导出目的
TelemetryContext开始召回管理的孩子跨度
TelemetrySpan记录属性、事件和地位;也作为儿童背景
SpanOptions扩展名和可选起始属性
SpanAttributes 编号 : AttributeValue打开适配器级属性包和支持的值
SpanStatus明确 ok 或者说 error 状态
NOOP_TELEMETRY_CONTEXT共有的对残疾遥测的被动语境
InMemoryTelemetryContext具有确定性过程的参考适配器-本地记录
RecordedTelemetrySpan正常捕获的跨度快照
RecordedTelemetryEvent正常捕获的事件快照

方案定义和推论

导出目的
defineTelemetrySchema()可序列化计划数据的类型化身份帮助器
createTypedSpanStarter()将父上下文绑入一个或多个术语表
TypedSpanStarter精确的启动类型, 递归带子的回调
TelemetrySchemaDefinition顶级方案形状
TelemetrySpanDefinitionSpan 元数据、 父数据、 属性、 事件和状态规则
TelemetryAttributeType支持的scalar 和数组类型名称
TelemetryAttributeMetadata描述、敏感性和主要元数据
TelemetryAttributeDefinition属性类型、允许的值、示例和元数据
TelemetryStartAttributeDefinition以要求开始属性定义
TelemetryEventAttributeDefinition事件属性定义与要求
TelemetryEventDefinition事件描述和属性定义
TelemetryParentDefinition开放的、外部的、或有限的 " 母性 " 规则
TelemetrySchemaSpanName宣布的跨度名称的结合
TelemetrySchemaSpanStartAttributes精确推断一个跨度的起始属性
TelemetrySchemaSpanEndAttributes一个跨度的可选推断端属性
TelemetrySchemaSpanEventName一分一秒宣布的活动合并
TelemetrySchemaSpanEventAttributes一个事件的精确推断属性
SchemaTelemetrySpan宽视限为 1 个方案间距
TelemetrySchemaSpanUnion在计划中歧视所有阶段的结合
InferStartAttributes从初始定义推断出的必要值和可选值
InferOptionalAttributes从终端定义推断出来的可选值
InferEventAttributes从事件定义推断出的必要值和可选值
InferRequiredAndOptionalAttributes必要定义的共同推论效用
ExactTelemetryAttributes在预期属性集之外拒绝密钥

测试子路径

导出目的
createTelemetryAdapterConformance()创建独立运行的适配器
TelemetryAdapterFixture一个案件的新背景和普通快照阅读器
TelemetryAdapterFixtureFactory创建孤立的固定装置
TelemetryAdapterConformanceCase测试跑者执行的分组案件

发展

从此包目录 :

bun run test
bun run build

仓库全库类型检查、格式化、林地化和烟雾检查:

bun run check

许可证

麻省理工学院

版本与发布记录

@code-yeongyu/senpi-telemetry 共发布 174 个版本,首次发布于 2026/08/13;过去 12 个月发布了 174 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2026.11.9-2latest2026/11/091 天前
2026.11.92026/11/091 天前
2026.11.6-32026/11/091 天前
2026.11.6-22026/11/082 天前
2026.11.6-12026/11/073 天前
2026.11.5-12026/11/064 天前

关于 @code-yeongyu/senpi-telemetry 的常见问题

@code-yeongyu/senpi-telemetry 是什么?

与供应商无关的遥测合同和用于pi的类型模式实用程序

如何安装 @code-yeongyu/senpi-telemetry?

在项目目录运行 npm install @code-yeongyu/senpi-telemetry,或使用 pnpm add / yarn add / bun add。

@code-yeongyu/senpi-telemetry 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@code-yeongyu/senpi-telemetry 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@code-yeongyu/senpi-telemetry 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.19.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@code-yeongyu/senpi-telemetry 可以商用吗?

@code-yeongyu/senpi-telemetry 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@code-yeongyu/senpi-telemetry 的下载量有多少?

根据 npm 官方下载统计,@code-yeongyu/senpi-telemetry 在 2026/10/10 – 2026/11/08 这 30 天内被下载 75,564 次,日均约 2,519 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@code-yeongyu/senpi-telemetry 还在维护吗?

最新版本 2026.11.9-2 发布于 2026/11/09(1 天前);至今共发布 174 个版本,其中过去 12 个月发布了 174 个;首次发布于 2026/08/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。