{"_id":"@aos-agent/telemetry","_rev":"4-4af6fa3ce80fd191fb0c53681780a215","name":"@aos-agent/telemetry","dist-tags":{"latest":"0.85.1"},"versions":{"0.84.2":{"name":"@aos-agent/telemetry","version":"0.84.2","keywords":["telemetry","tracing","observability"],"author":{"name":"Mario Zechner"},"license":"MIT","_id":"@aos-agent/telemetry@0.84.2","maintainers":[{"name":"aosagent","email":"guanwenpeng2001@gmail.com"}],"homepage":"https://github.com/guanwenpeng2001-bot/AOS-Agent#readme","bugs":{"url":"https://github.com/guanwenpeng2001-bot/AOS-Agent/issues"},"dist":{"shasum":"362e9dd847f4dd44ea41ecc0cb874fa6e844fbb1","tarball":"https://registry.npmjs.org/@aos-agent/telemetry/-/telemetry-0.84.2.tgz","fileCount":26,"integrity":"sha512-KHLcC6dvK/tZO4B/x7kKWrJy0Opunm9AaPk1Yso8pxM7h2Vmw6cEhfUFGmGpovn0eDDysXkMZDAZj+M5eUDfEw==","signatures":[{"sig":"MEUCIQCpf/ZWNAkNSsIWHeJIDrOntYZ6pA1QeA1k47ZuC7v+aQIgRa95W1r+YvrW11gsLyYYkQQyQS7qhd2PrY4WwFsGvro=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":157947},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js"}},"scripts":{"test":"vitest --run","build":"tsgo -p tsconfig.build.json","clean":"shx rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"aosagent","email":"guanwenpeng2001@gmail.com"},"repository":{"url":"git+https://github.com/guanwenpeng2001-bot/AOS-Agent.git","type":"git","directory":"packages/telemetry"},"_npmVersion":"12.0.2","description":"Vendor-neutral telemetry contracts and typed schema utilities for AOS Agent","directories":{},"_nodeVersion":"24.18.1","_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.9","@types/node":"24.12.4"},"_npmOperationalInternal":{"tmp":"tmp/telemetry_0.84.2_1786323778875_0.08318011236196177","host":"s3://npm-registry-packages-npm-production"}},"0.84.3":{"name":"@aos-agent/telemetry","version":"0.84.3","keywords":["telemetry","tracing","observability"],"author":{"name":"Mario Zechner"},"license":"MIT","_id":"@aos-agent/telemetry@0.84.3","maintainers":[{"name":"aosagent","email":"guanwenpeng2001@gmail.com"}],"homepage":"https://github.com/guanwenpeng2001-bot/AOS-Agent#readme","bugs":{"url":"https://github.com/guanwenpeng2001-bot/AOS-Agent/issues"},"dist":{"shasum":"68375a0549e45be754755786c08686c5c4f4e9a9","tarball":"https://registry.npmjs.org/@aos-agent/telemetry/-/telemetry-0.84.3.tgz","fileCount":26,"integrity":"sha512-0nyHyEqU9vQsO8awuafghdzD1vbBHod664sEvgdSJH7kvncKiVSsvv2g8VBD09lLrINVBaQ/w44ZhpqPkhbSMA==","signatures":[{"sig":"MEUCIQDkN66vtKpDipFLht5wpwy3Jux2jWW7uoCbFFXTP8uioQIgPxN4Hdh9ZCyrMq7WCrNqAYvdkQyHlNoqLrYLUiBCr0Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aos-agent%2ftelemetry@0.84.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":157947},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js"}},"gitHead":"d92430128236cc1f285dcbb4f03ddd56ed81f8da","scripts":{"test":"vitest --run","build":"tsgo -p tsconfig.build.json","clean":"shx rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:97eb5eb3-c953-40bc-a8d7-392e21f14e84"}},"repository":{"url":"git+https://github.com/guanwenpeng2001-bot/AOS-Agent.git","type":"git","directory":"packages/telemetry"},"_npmVersion":"11.5.1","description":"Vendor-neutral telemetry contracts and typed schema utilities for AOS Agent","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.9","@types/node":"24.12.4"},"_npmOperationalInternal":{"tmp":"tmp/telemetry_0.84.3_1786383941474_0.8134936112182785","host":"s3://npm-registry-packages-npm-production"}},"0.85.0":{"name":"@aos-agent/telemetry","version":"0.85.0","keywords":["telemetry","tracing","observability"],"author":{"name":"AOS Agent"},"license":"MIT","_id":"@aos-agent/telemetry@0.85.0","maintainers":[{"name":"aosagent","email":"guanwenpeng2001@gmail.com"}],"homepage":"https://github.com/guanwenpeng2001-bot/AOS-Agent#readme","bugs":{"url":"https://github.com/guanwenpeng2001-bot/AOS-Agent/issues"},"dist":{"shasum":"aed39098d0acfcb61ab077e230971f7f28a6bc93","tarball":"https://registry.npmjs.org/@aos-agent/telemetry/-/telemetry-0.85.0.tgz","fileCount":30,"integrity":"sha512-KewX9lmMePEJkIchIQ8P2Qz6N5HfdcEUzWfcnliZLaxfpZORFY2v/JVsOSdyLzRjuHSGwC7dM4ZCYbXk/gp0Cg==","signatures":[{"sig":"MEUCIQCIw90MwEF4/05TLTLPJs07rmZVEHDCFzZkOlBKU5EkSAIgOhP4lS8vFREtr20iDE4aQ6YDDQekOZpU3nnIXfRn0p8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aos-agent%2ftelemetry@0.85.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":237530},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js"}},"gitHead":"a305bd6d376b447cbdc0b92711a54e9778d24695","scripts":{"test":"vitest --run","build":"tsgo -p tsconfig.build.json","clean":"shx rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:97eb5eb3-c953-40bc-a8d7-392e21f14e84"}},"repository":{"url":"git+https://github.com/guanwenpeng2001-bot/AOS-Agent.git","type":"git","directory":"packages/telemetry"},"_npmVersion":"11.5.1","description":"Vendor-neutral telemetry contracts and typed schema utilities for AOS Agent","directories":{},"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.9","@types/node":"24.12.4"},"_npmOperationalInternal":{"tmp":"tmp/telemetry_0.85.0_1788326547100_0.27264888310285174","host":"s3://npm-registry-packages-npm-production"}},"0.85.1":{"_id":"@aos-agent/telemetry@0.85.1","bugs":{"url":"https://github.com/guanwenpeng2001-bot/AOS-Agent/issues"},"dist":{"shasum":"c7009cc09cb7e5b8ec87643f62c84a176390c6cc","tarball":"https://registry.npmjs.org/@aos-agent/telemetry/-/telemetry-0.85.1.tgz","fileCount":30,"integrity":"sha512-0HCY56n6rlpEV8pIiEPqctjYV7k8OQ2W3tQLjxbGlFL1lBL5TY/Cvm6fhgZ1qxM33onzg/+kXA0Qi9ZqUP2Ulg==","signatures":[{"sig":"MEUCIQDnfpJl5BW8t+AF3eeNHRZk8TJfSKGRXQvhF1hoJ7eUqwIgGSuGqcu5p6W9EKbqfSygiVFgWMLbQbsyUPjK5CPKrsI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEZ7q/ADg5KHC09nUSO7peQ4fdNX/DPFoKjW8r5jF1lCAiEApJN3ooBm+WLg/tOAmrfzAB7PNnVD/LuqEdHFGcSaNEQ="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aos-agent%2ftelemetry@0.85.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":237530},"main":"./dist/index.js","name":"@aos-agent/telemetry","type":"module","types":"./dist/index.d.ts","author":{"name":"AOS Agent"},"engines":{"node":">=22.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js"}},"gitHead":"8fc01dea402bced66d545cf6febddcd944d8943b","license":"MIT","scripts":{"test":"vitest --run","build":"tsgo -p tsconfig.build.json","clean":"shx rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"version":"0.85.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:97eb5eb3-c953-40bc-a8d7-392e21f14e84"}},"homepage":"https://github.com/guanwenpeng2001-bot/AOS-Agent#readme","keywords":["telemetry","tracing","observability"],"repository":{"url":"git+https://github.com/guanwenpeng2001-bot/AOS-Agent.git","type":"git","directory":"packages/telemetry"},"_npmVersion":"11.5.1","description":"Vendor-neutral telemetry contracts and typed schema utilities for AOS Agent","directories":{},"maintainers":[{"name":"aosagent","email":"guanwenpeng2001@gmail.com"}],"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"4.1.9","@types/node":"24.12.4"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/telemetry_0.85.1_1788451969740_0.05665604798274493"}}},"time":{"created":"2026-08-10T01:02:58.733Z","modified":"2026-09-03T16:12:50.195Z","0.84.2":"2026-08-10T01:02:59.015Z","0.84.3":"2026-08-10T17:45:41.625Z","0.85.0":"2026-09-02T05:22:27.226Z","0.85.1":"2026-09-03T16:12:49.853Z"},"bugs":{"url":"https://github.com/guanwenpeng2001-bot/AOS-Agent/issues"},"author":{"name":"AOS Agent"},"license":"MIT","homepage":"https://github.com/guanwenpeng2001-bot/AOS-Agent#readme","keywords":["telemetry","tracing","observability"],"repository":{"url":"git+https://github.com/guanwenpeng2001-bot/AOS-Agent.git","type":"git","directory":"packages/telemetry"},"description":"Vendor-neutral telemetry contracts and typed schema utilities for AOS Agent","maintainers":[{"name":"aosagent","email":"guanwenpeng2001@gmail.com"}],"readme":"# @aos-agent/telemetry\n\nVendor-neutral telemetry contracts and typed schema utilities for AOS Agent packages.\n\nThis package provides:\n\n- an explicit, callback-based `TelemetryContext` / `TelemetrySpan` contract;\n- a shared `NOOP_TELEMETRY_CONTEXT`;\n- a reference `InMemoryTelemetryContext` implementation;\n- serializable schema definitions with inferred TypeScript types;\n- a dependency-free OTLP/HTTP JSON exporter with bounded batching and derived basic metrics;\n- no global current-span state or dependency on a telemetry SDK.\n\nApplications can use the in-memory reference or provide an adapter for OpenTelemetry, Sentry, logs, or another backend. AOS Agent packages pass telemetry contexts explicitly and define their domain schemas separately.\n\n`OtlpHttpTelemetryContext` exports completed spans to `/v1/traces` and derives run, AI-request, and tool count/duration metrics for `/v1/metrics`. Its queue is bounded, drops the oldest span on overflow, and contains network failures as diagnostic counters. Call `shutdown()` to stop its unreferenced timer and flush queued telemetry.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Telemetry Concepts](#telemetry-concepts)\n- [Core Context API](#core-context-api)\n- [Adapter Contract](#adapter-contract)\n- [No-op Context](#no-op-context)\n- [In-Memory Reference Adapter](#in-memory-reference-adapter)\n- [Adapter Conformance](#adapter-conformance)\n- [Typed Schemas](#typed-schemas)\n  - [Start and Completion Attributes](#start-and-completion-attributes)\n- [Schema Metadata](#schema-metadata)\n- [AOS Agent Package Integration](#aos-agent-package-integration)\n- [Security and Portability](#security-and-portability)\n- [API Reference](#api-reference)\n- [Development](#development)\n- [License](#license)\n\n## Installation\n\n```bash\nnpm install @aos-agent/telemetry\n```\n\n## Telemetry Concepts\n\nTelemetry describes what a program did while it was running. This package models that work using spans, attributes, events, statuses, and explicit context:\n\n| Concept | Plain-language meaning |\n|---|---|\n| **Span** | A timed record of one operation, such as loading an account or making an AI request. It begins before the work and ends when the work finishes. |\n| **Parent and child spans** | Operations can contain smaller operations. A request span might contain a cache lookup and a database query. Together they form a tree showing where time was spent. |\n| **Attribute** | A named fact attached to a span, such as `provider: \"openai\"`, `cache.hit: true`, or `item_count: 12`. Attributes describe the operation and its result. |\n| **Event** | A named occurrence at a point during a span, such as `retry.scheduled` or `cache.lookup`. Events have no duration and may carry their own attributes. |\n| **Status** | The operation's outcome: `ok` or `error`. An error status may include an error name and message. |\n| **Context** | A handle identifying where new work belongs in the span tree. Starting a span from a context makes it a child of that context. |\n\nFor example, loading an account could produce this telemetry:\n\n```text\nexample.account.load                         span\n├─ attributes: account.id=123, found=true   facts about the span\n├─ event: example.cache.lookup              occurrence during the span\n│  └─ attribute: cache.hit=false            fact about the event\n└─ status: ok                               final outcome\n```\n\nA span is diagnostic data, not business state. Recording it must not change whether the account load runs, succeeds, fails, or is persisted. An adapter translates these generic concepts into the corresponding concepts used by OpenTelemetry, Sentry, logs, or another backend.\n\n## Core Context API\n\nA `TelemetryContext` starts a span around a callback. The callback receives a `TelemetrySpan`, which is also the explicit parent context for child spans.\n\n```typescript\nimport {\n  NOOP_TELEMETRY_CONTEXT,\n  type TelemetryContext,\n} from '@aos-agent/telemetry';\n\nasync function loadAccount(\n  accountId: string,\n  telemetryContext: TelemetryContext = NOOP_TELEMETRY_CONTEXT,\n) {\n  return telemetryContext.startSpan(\n    {\n      name: 'example.account.load',\n      attributes: { 'example.account.id': accountId },\n    },\n    async (span) => {\n      const account = await readAccount(accountId);\n      span.setAttributes({ 'example.account.found': account !== undefined });\n      return account;\n    },\n  );\n}\n```\n\nPass the callback span to lower-level work to create explicit nesting:\n\n```typescript\nreturn telemetryContext.startSpan({ name: 'example.parent' }, async (parentSpan) => {\n  return parentSpan.startSpan({ name: 'example.child' }, async (childSpan) => {\n    childSpan.addEvent('example.cache.lookup', { 'example.cache.hit': true });\n    return performWork();\n  });\n});\n```\n\nThere is no public `end()` method. `startSpan()` owns settlement and keeps the span open until the callback's value or promise settles. For an expected failure represented by a normal return value, set the status explicitly:\n\n```typescript\nreturn telemetryContext.startSpan({ name: 'example.save' }, async (span) => {\n  const result = await save();\n  if (!result.ok) {\n    span.setStatus({\n      status: 'error',\n      error: { name: 'SaveError', message: result.reason },\n    });\n  }\n  return result;\n});\n```\n\n## Adapter Contract\n\nAn adapter implements `TelemetryContext` and bridges the generic API to its backend. It must:\n\n- create a child span and invoke the callback synchronously, exactly once;\n- preserve the callback's returned value and rejection value, returning a promise rejected with the same value after a synchronous throw;\n- keep the native span open until a returned promise settles;\n- treat normal completion as `ok` and throws/rejections as errors unless an explicit status was set;\n- make repeated `setStatus()` calls last-write-wins;\n- merge `setAttributes()` calls, with later defined values replacing earlier values and `undefined` ignored;\n- make recording methods synchronous, passive, and non-throwing;\n- ignore calls made after settlement;\n- ignore a failed recording call atomically, suppress backend failures, and still execute the business callback exactly once.\n\nAdapters may activate backend-native ambient context internally for automatic instrumentation, but AOS Agent code always propagates the parent through `TelemetryContext` arguments. Exporter buffering, flushing, sampling, backend IDs, and backend-specific context objects belong to the adapter. Use the [adapter conformance suite](#adapter-conformance) to check these observable semantics.\n\n## No-op Context\n\nUse `NOOP_TELEMETRY_CONTEXT` when telemetry is optional:\n\n```typescript\nimport { NOOP_TELEMETRY_CONTEXT } from '@aos-agent/telemetry';\n\nconst result = await NOOP_TELEMETRY_CONTEXT.startSpan(\n  { name: 'example.operation' },\n  () => runOperation(),\n);\n```\n\nThe no-op context:\n\n- invokes callbacks synchronously;\n- preserves returned values and asynchronous rejections, and converts a synchronous throw to a promise rejected with the same value;\n- uses one shared frozen inert span, including for nested spans;\n- does not inspect or retain names, attributes, events, or statuses.\n\n## In-Memory Reference Adapter\n\n`InMemoryTelemetryContext` is the backend-neutral reference implementation. It is useful for tests, local diagnostics, and applications that intentionally want process-local capture without an exporter:\n\n```typescript\nimport { InMemoryTelemetryContext } from '@aos-agent/telemetry';\n\nconst telemetry = new InMemoryTelemetryContext();\n\nawait telemetry.startSpan(\n  { name: 'example.operation', attributes: { input: 'demo' } },\n  async (span) => {\n    span.addEvent('example.started');\n    span.setAttributes({ output_count: 3 });\n  },\n);\n\nconsole.log(telemetry.getSpans());\n```\n\n`getSpans()` returns detached snapshots in span-start order. Each `RecordedTelemetrySpan` contains a deterministic numeric ID, parent ID, merged attributes, ordered events, final status, settlement state, and deterministic end sequence. It records no timestamps.\n\nThe adapter is safe to use as an ordinary `TelemetryContext`, but storage is unbounded and process-local. Create a fresh instance to isolate tests or recording scopes, and do not capture sensitive attributes unless the caller's data policy allows them.\n\n## Adapter Conformance\n\n`@aos-agent/telemetry/testing` exports a runner-independent conformance suite modeled as grouped cases. A fixture supplies a fresh context and converts its backend's finished spans into normalized `RecordedTelemetrySpan` snapshots:\n\n```typescript\nimport {\n  createTelemetryAdapterConformance,\n  type TelemetryAdapterFixture,\n} from '@aos-agent/telemetry/testing';\nimport { describe, it } from 'vitest';\n\nconst conformance = createTelemetryAdapterConformance(async () => {\n  const adapter = createMyTelemetryAdapter();\n  return {\n    context: adapter.context,\n    getSpans: async () => adapter.normalizedSpans(),\n    async [Symbol.asyncDispose]() {\n      await adapter.close();\n    },\n  } satisfies TelemetryAdapterFixture;\n});\n\nfor (const group of new Set(conformance.map((testCase) => testCase.group))) {\n  describe(group, () => {\n    for (const testCase of conformance.filter((candidate) => candidate.group === group)) {\n      it(testCase.name, () => testCase.run());\n    }\n  });\n}\n```\n\nThe suite checks synchronous single admission, result and rejection identity, automatic and explicit status, attribute merging, event ordering, inert post-settlement calls, nested and concurrent parentage, and suppression of unreadable telemetry payload failures. `getSpans()` may flush an asynchronous exporter before returning. The testing subpath uses Node's assertion APIs; the root telemetry package remains runtime-neutral.\n\n## Typed Schemas\n\nThe low-level span API intentionally accepts open names and attribute bags so adapters remain generic. Domain packages can define closed, serializable schemas and infer exact TypeScript types from them.\n\n```typescript\nimport {\n  createTypedSpanStarter,\n  defineTelemetrySchema,\n} from '@aos-agent/telemetry';\n\nexport const EXAMPLE_TELEMETRY_SCHEMA = defineTelemetrySchema({\n  version: 1,\n  spans: {\n    'example.read': {\n      description: 'Read one resource',\n      parents: { kind: 'any' },\n      startAttributes: {\n        'example.resource': {\n          type: 'string',\n          required: true,\n          values: ['account', 'project'],\n          description: 'Resource kind',\n        },\n      },\n      endAttributes: {\n        'example.item_count': {\n          type: 'number',\n          description: 'Number of returned items',\n        },\n      },\n      events: {\n        'example.cache': {\n          description: 'Cache lookup result',\n          attributes: {\n            'example.cache.hit': {\n              type: 'boolean',\n              required: true,\n              description: 'Whether the cache contained the resource',\n            },\n          },\n        },\n      },\n      status: {\n        default: 'ok',\n        errorWhen: 'The read throws or returns an error result',\n      },\n    },\n  },\n} as const);\n\nconst startSpan = createTypedSpanStarter(\n  telemetryContext,\n  [EXAMPLE_TELEMETRY_SCHEMA],\n);\n```\n\nThe starter exposes one overload per span and checks names and attributes at compile time. Union-valued names must be narrowed before a call, preserving the relationship between each runtime name and its attribute schema. Its callback receives a child starter over the same schemas, already bound to the callback span:\n\n```typescript\nawait startSpan(\n  'example.read',\n  { 'example.resource': 'account' },\n  async (span, startChildSpan) => {\n    span.addEvent('example.cache', { 'example.cache.hit': true });\n    const accounts = await readAccounts();\n    span.setAttributes({ 'example.item_count': accounts.length });\n\n    await startChildSpan(\n      'example.read',\n      { 'example.resource': 'project' },\n      async (childSpan) => {\n        const projects = await readProjects();\n        childSpan.setAttributes({ 'example.item_count': projects.length });\n      },\n    );\n\n    return accounts;\n  },\n);\n```\n\n### Start and Completion Attributes\n\n`startAttributes` and `endAttributes` describe when an attribute is normally known, not separate runtime storage:\n\n| Schema field | How values are recorded | Requiredness |\n|---|---|---|\n| `startAttributes` | Passed in the typed starter's `attributes` argument when the span is created | Each definition explicitly sets `required: true` or `false` |\n| `endAttributes` | Added later through the schema-scoped span's `setAttributes()` method | Always optional |\n\nBoth sets become ordinary attributes on the same backend span. There is no separate end-attribute payload or end callback. In the preceding example, `example.resource` is known when `example.read` starts, while `example.item_count` is known only after `readAccounts()` returns:\n\n```typescript\nawait startSpan(\n  'example.read',\n  { 'example.resource': 'account' }, // required start attribute\n  async (span) => {\n    const accounts = await readAccounts();\n    span.setAttributes({\n      'example.item_count': accounts.length, // optional completion attribute\n    });\n    return accounts;\n  },\n); // resolving the callback settles the span\n```\n\n“End” means completion enrichment: an end attribute may be set at any point while the callback is active, and it may be omitted when unavailable. Calling `setAttributes()` zero times is valid. This matters for early failures, cancellation, and provider-specific data that may not exist on every path.\n\nRepeated `setAttributes()` calls merge into the same attribute bag. A later defined value replaces an earlier value for the same key, while `undefined` is ignored. The schema-scoped method accepts only the current span's declared end attributes.\n\nAttributes do not end the span. Returning, resolving, throwing, or rejecting from the callback controls settlement; `startSpan()` performs the actual end operation. Adapter calls made after settlement are inert.\n\nA starter can compose multiple independently versioned schemas:\n\n```typescript\nimport { AGENT_TELEMETRY_SCHEMAS } from '@aos-agent/agent-core';\n\nconst startAgentSpan = createTypedSpanStarter(\n  telemetryContext,\n  AGENT_TELEMETRY_SCHEMAS,\n);\n```\n\nInline schema arrays retain their tuple types automatically. Separately declared arrays should use `as const`. Literal duplicate span names across the array are rejected at compile time; schemas are not merged, inspected, or retained at runtime.\n\nSchema-derived types reject missing required attributes, unknown keys, invalid closed-set values, undeclared events, and attributes on empty schemas. End attributes are always optional enrichment; the type system does not require `setAttributes()` to be called.\n\n`defineTelemetrySchema()` is a typed identity function. It returns ordinary JSON-serializable data and performs no runtime validation or parent-rule enforcement.\n\n## Schema Metadata\n\nSupported attribute types are:\n\n- `string`, `number`, and `boolean`;\n- `string[]`, `number[]`, and `boolean[]`.\n\nAttribute definitions support:\n\n- `values`: a closed set for scalar values;\n- `elementValues`: a closed set for array elements;\n- `examples`: documentation examples;\n- `sensitive`: marks data requiring special handling;\n- `cardinality`: records expected `low` or `high` cardinality.\n\nStart and event attributes declare `required`. End attributes do not; see [Start and Completion Attributes](#start-and-completion-attributes).\n\nParent metadata is descriptive schema data:\n\n- `{ kind: 'any' }`: root or any caller span;\n- `{ kind: 'root_or_external' }`: root or a caller-owned span outside the schema;\n- `{ kind: 'spans', spans: [...] }`: only the listed schema spans.\n\nAdapters do not need to understand schema objects. Instrumentation helpers and tests use them to keep emitted names and attributes consistent.\n\n## AOS Agent Package Integration\n\nPackage ownership is intentionally split:\n\n- `@aos-agent/telemetry` owns the vendor-neutral contract, no-op and in-memory reference contexts, schema utilities, and adapter conformance suite;\n- `@aos-agent/ai` accepts and propagates `telemetryContext` in provider request options but owns no telemetry schema;\n- `@aos-agent/agent-core` owns and exports the AI-request and harness schemas, their combined readonly schema tuple, and typed span helpers.\n\n```typescript\nimport {\n  AGENT_TELEMETRY_SCHEMAS,\n  AI_TELEMETRY_SCHEMA,\n  HARNESS_TELEMETRY_SCHEMA,\n  startAiSpan,\n  startHarnessSpan,\n} from '@aos-agent/agent-core';\n```\n\nThe schemas use package-owned technical names `aos.ai.*`, `aos.harness.*`, and `aos.session.*`. Adapters may translate them to backend conventions without changing the emitted vocabulary.\n\n## Security and Portability\n\nTelemetry is process-local diagnostics, not durable application state. Do not persist a `TelemetryContext`, `TelemetrySpan`, or backend-native trace object in records, messages, snapshots, or deferred handles.\n\nAttribute values are intentionally limited to primitive scalars and arrays. Domain instrumentation should avoid prompts, completions, tool arguments or output, file contents, provider payloads, headers, credentials, and free-form error details unless its schema and data policy explicitly allow them.\n\nThe package does not use `AsyncLocalStorage` or another runtime-specific ambient context API. It is suitable for Node.js, Bun, browsers, and workers; backend adapters remain responsible for their own runtime compatibility.\n\n## API Reference\n\n### Core types and values\n\n| Export | Purpose |\n|---|---|\n| `TelemetryContext` | Starts callback-managed child spans |\n| `TelemetrySpan` | Records attributes, events, and status; also acts as a child context |\n| `SpanOptions` | Span name and optional start attributes |\n| `SpanAttributes` / `AttributeValue` | Open adapter-level attribute bag and supported values |\n| `SpanStatus` | Explicit `ok` or `error` status |\n| `NOOP_TELEMETRY_CONTEXT` | Shared passive context for disabled telemetry |\n| `InMemoryTelemetryContext` | Reference adapter with deterministic process-local recording |\n| `RecordedTelemetrySpan` | Normalized captured span snapshot |\n| `RecordedTelemetryEvent` | Normalized captured event snapshot |\n\n### Schema definitions and inference\n\n| Export | Purpose |\n|---|---|\n| `defineTelemetrySchema()` | Typed identity helper for serializable schema data |\n| `createTypedSpanStarter()` | Binds a parent context to one or more schema vocabularies |\n| `TypedSpanStarter` | Exact starter type with recursively child-bound callbacks |\n| `TelemetrySchemaDefinition` | Top-level schema shape |\n| `TelemetrySpanDefinition` | Span metadata, parents, attributes, events, and status rule |\n| `TelemetryAttributeType` | Supported scalar and array type names |\n| `TelemetryAttributeMetadata` | Description, sensitivity, and cardinality metadata |\n| `TelemetryAttributeDefinition` | Attribute type, allowed values, examples, and metadata |\n| `TelemetryStartAttributeDefinition` | Start attribute definition with requiredness |\n| `TelemetryEventAttributeDefinition` | Event attribute definition with requiredness |\n| `TelemetryEventDefinition` | Event description and attribute definitions |\n| `TelemetryParentDefinition` | Open, external-root, or finite schema-parent rule |\n| `TelemetrySchemaSpanName` | Union of declared span names |\n| `TelemetrySchemaSpanStartAttributes` | Exact inferred start attributes for one span |\n| `TelemetrySchemaSpanEndAttributes` | Optional inferred end attributes for one span |\n| `TelemetrySchemaSpanEventName` | Union of events declared by one span |\n| `TelemetrySchemaSpanEventAttributes` | Exact inferred attributes for one event |\n| `SchemaTelemetrySpan` | Span view restricted to one schema span |\n| `TelemetrySchemaSpanUnion` | Discriminated union of all spans in a schema |\n| `InferStartAttributes` | Required and optional values inferred from start definitions |\n| `InferOptionalAttributes` | Optional values inferred from end definitions |\n| `InferEventAttributes` | Required and optional values inferred from event definitions |\n| `InferRequiredAndOptionalAttributes` | Shared inference utility for definitions with requiredness |\n| `ExactTelemetryAttributes` | Rejects keys outside an expected attribute set |\n\n### Testing subpath\n\n| Export | Purpose |\n|---|---|\n| `createTelemetryAdapterConformance()` | Creates runner-independent adapter conformance cases |\n| `TelemetryAdapterFixture` | Fresh context and normalized snapshot reader for one case |\n| `TelemetryAdapterFixtureFactory` | Creates isolated fixtures |\n| `TelemetryAdapterConformanceCase` | Grouped case that test runners execute |\n\n## Development\n\nFrom this package directory:\n\n```bash\nnpm test\nnpm run build\n```\n\nRepository-wide type checking, formatting, linting, and smoke checks run with:\n\n```bash\nnpm run check\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}