# @code-yeongyu/senpi-telemetry 中文文档

规范地址：https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/

版本：2026\.11\.9-2
npm 元数据更新时间：2026-11-09T06:45:32.039Z
中文译文更新时间：2026-11-10T05:59:13.293Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40code-yeongyu/senpi-telemetry
原文对照：https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/?lang=original
项目主页：https://github.com/code-yeongyu/senpi#readme
源码仓库：https://github.com/code-yeongyu/senpi

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：57.8 kB，14 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.19\.0
- 运行依赖：0 个
- 首次发布：2026-08-13T09:53:35.913Z
- 最新版本发布：2026-11-09T06:45:31.736Z
- 近 30 天下载量：75564（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：174（近 12 个月 174 个）

## 中文简介

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

## 安装

```sh
npm install @code-yeongyu/senpi-telemetry
```

也可以使用：`pnpm add @code-yeongyu/senpi-telemetry`、`yarn add @code-yeongyu/senpi-telemetry`、`bun add @code-yeongyu/senpi-telemetry`

## README

# @earendil-works/pi-遥测

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

本套件提供:

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

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

## 目录

-   [安装](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-installation)
-   [遥测概念](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-telemetry-concepts)
-   [核心内容 API](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-core-context-api)
-   [适配器合同](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-adapter-contract)
-   [无上下文](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-no-op-context)
-   [记忆参考适应器](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-in-memory-reference-adapter)
-   [适配器](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-adapter-conformance)
-   [已键入Schemas](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-typed-schemas)
    -   [开始和完成属性](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-start-and-completion-attributes)
-   [Schema 元数据](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-schema-metadata)
-   [Pi 软件包集成](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-pi-package-integration)
-   [安全和可移动性](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-security-and-portability)
-   [API 参考](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-api-reference)
-   [发展](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-development)
-   [许可证](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-license)

## 安装

```bash
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. 背景情况** | 指向横跨树上新工作所在的手柄。 从上下文开始的一段时期使它成为上下文的孩子. |

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

```text
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`,这也是孩子跨度的明确的父母背景.

```typescript
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;
    },
  );
}
```

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

```typescript
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()` 拥有和解并保持跨度,直到召回值或承诺达成为止。 对于以正常返回值为代表的预期失败,明确规定状态:

```typescript
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,后端特定上下文对象属于适配器. 使用 [适配器套装](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-adapter-conformance) 检查这些可见的语义.

## 无上下文

使用 `NOOP_TELEMETRY_CONTEXT` 当遥测为可选时:

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

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

无上下文 :

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

## 记忆参考适应器

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

```typescript
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` 快照 :

```typescript
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.

```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],
);
```

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

```typescript
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()` 返回 :

```typescript
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()` 进行实际的终端操作。 在和解后拨打的适配电话是无效的.

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

```typescript
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`。结尾属性不;见 [开始和完成属性](https://npmcn.com/package/%40code-yeongyu/senpi-telemetry/#readme-start-and-completion-attributes)。 。 。 .

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

-   `{ 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, 和打出跨度帮助器.

```typescript
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` | 顶级方案形状 |
| `TelemetrySpanDefinition` | Span 元数据、 父数据、 属性、 事件和状态规则 |
| `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` | 测试跑者执行的分组案件 |

## 发展

从此包目录 :

```bash
bun run test
bun run build
```

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

```bash
bun run check
```

## 许可证

麻省理工学院

## 常见问题

### @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 和提交记录判断。

