npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cuylabs/agent-a365-observability

v4.4.0

Published

Microsoft Agent 365 observability adapter for @cuylabs/agent-core

Downloads

999

Readme

@cuylabs/agent-a365-observability

Microsoft Agent 365 observability adapter for @cuylabs/agent-core.

This package connects agent-core's portable OpenTelemetry spans to Microsoft's Agent 365 observability SDK without putting Microsoft SDK types in agent-core.

It does four things:

  • starts Microsoft Agent 365 Observability;
  • wires the Agent 365 exporter token resolver;
  • returns a small createAgent({ tracing }) config fragment for stable agent metadata;
  • wraps each request in Agent 365 baggage so spans include tenant, agent, conversation, channel, and caller identity.

For the deeper design, read docs/README.md.

Install

pnpm add @cuylabs/agent-a365-observability @microsoft/agents-a365-observability @microsoft/agents-a365-runtime

Usage

import { createAgent } from "@cuylabs/agent-core";
import {
  createA365TracingConfig,
  initA365Observability,
  runWithA365Context,
  runWithA365TurnContext,
} from "@cuylabs/agent-a365-observability";

const observability = await initA365Observability({
  serviceName: "email-agent-service",
  serviceVersion: "1.0.0",
  configuration: {
    exporterEnabled: true,
    logLevel: "info",
  },
  tokenResolver: async (agentId, tenantId) => {
    return getObservabilityToken(agentId, tenantId);
  },
});

const agent = createAgent({
  name: "email-assistant",
  model,
  tracing: createA365TracingConfig({
    agentId: "agent-456",
    agentDescription: "Organizes email and calendar work",
    agentVersion: "1.0.0",
  }),
});

await runWithA365Context(
  {
    tenantId: "tenant-123",
    agentId: "agent-456",
    conversationId: "conversation-789",
    sessionId: "session-789",
    channelName: "msteams",
  },
  async () => {
    for await (const event of agent.chat("session-789", "Find urgent email")) {
      // stream events to your channel
    }
  },
);

await agent.close();
await observability.shutdown();

M365 / Teams bot turns

When your bot uses @microsoft/agents-hosting TurnContext, use the TurnContext helper so tenant, agent, conversation, channel, and user identity are derived from the incoming activity:

await runWithA365TurnContext(
  context, // TurnContext from CloudAdapter
  {
    agentId: "agent-456",
    agentDescription: "Organizes email and calendar work",
    agentVersion: "1.0.0",
    sessionId,
  },
  async () => {
    for await (const event of agent.chat(sessionId, context.activity.text)) {
      // stream events to the channel
    }
  },
);

If you use @cuylabs/agent-channel-m365, this wrapper is built into the channel adapter:

const m365 = createM365ChannelAdapter({
  agent,
  a365Observability: {
    agentId: "agent-456",
    agentDescription: "Organizes email and calendar work",
    agentVersion: "1.0.0",
  },
});

The host process still needs to call initA365Observability(...) once during startup so the Microsoft exporter and token resolver are registered.

Shape

The integration has three separate pieces:

  1. initA365Observability(...) starts Microsoft's exporter and baggage span processor once at host startup.
  2. createA365TracingConfig(...) feeds agent-core's createAgent({ tracing }) contract.
  3. runWithA365Context(...) or runWithA365TurnContext(...) binds per-request Agent 365 baggage before agent.chat() runs.

Use agent-core for portable OpenTelemetry spans:

  • invoke_agent agent spans
  • execute_tool tool spans
  • AI SDK model spans nested under the agent turn

Use this package for Agent 365-specific context on those spans:

  • microsoft.tenant.id
  • gen_ai.agent.id
  • microsoft.session.id
  • gen_ai.conversation.id
  • channel and caller attributes
  • A2A caller-agent attributes such as microsoft.a365.caller.agent.id

For multi-tenant agents, prefer runWithA365Context() over static tracing attributes. Static attributes are useful for stable agent metadata; baggage is the right place for per-request tenant and conversation identity.

Use extraBaggage only for additional dimensions that are not part of the standard Agent 365 identity set. Structured fields such as tenantId, agentId, conversationId, and userId win over conflicting extraBaggage keys.

Microsoft's baggage processor does not overwrite span attributes that agent-core already set. In normal @cuylabs/agent-channel-m365 usage this is fine because the channel's default session strategy uses the M365 conversation.id as the agent-core session ID. If you use custom M365 session mapping, gen_ai.conversation.id reflects the custom agent-core session ID. See docs/agent-core-otel.md for details.

Phoenix vs Agent 365

Phoenix is a normal OTLP destination. You pass a span processor/exporter into agent-core tracing, and agent-core owns the tracer provider lifecycle for that example.

Agent 365 is different. The Microsoft SDK owns the exporter and adds an Agent 365 span processor that copies baggage into span attributes. agent-core still emits the agent, tool, and AI SDK spans, while this package starts the Microsoft exporter and wraps each request with the tenant, agent, conversation, channel, and caller baggage that Agent 365 expects.

AI SDK Telemetry

agent-core uses AI SDK v7 telemetry and enables @ai-sdk/otel's GenAIOpenTelemetry integration by default. That gives you current GenAI-shaped model spans such as invoke_agent, agent_step, chat, and execute_tool, with attributes like gen_ai.operation.name, gen_ai.provider.name, model IDs, and token usage.

This package does not replace that model telemetry. It adds the Microsoft Agent 365 layer: exporter startup, token resolution, and baggage that flows microsoft.tenant.id, gen_ai.agent.id, conversation, channel, and caller identity onto the spans.

If you need to plug in another AI SDK telemetry integration, pass it through createA365TracingConfig():

const agent = createAgent({
  name: "email-assistant",
  model,
  tracing: createA365TracingConfig({
    agentId: "agent-456",
    telemetryIntegrations: [myIntegration],
  }),
});

Set useGenAIOpenTelemetry: false only when you intentionally want to use global AI SDK telemetry integrations or another model-span integration.

TurnContext Mapping

runWithA365TurnContext(...) follows Microsoft's agents-a365-observability-hosting helper behavior for M365 Activity fields. Some mappings look surprising if read as generic Bot Framework fields:

  • activity.serviceUrl maps to microsoft.conversation.item.link.
  • activity.recipient.role maps to gen_ai.agent.description.
  • activity.from.agenticUserId maps to user.email.
  • activity.channelIdSubChannel maps to microsoft.channel.link.

Pass explicit runWithA365TurnContext options when your host has more precise values, such as a real Teams message deep link for conversationItemLink. Caller-agent attributes and host-owned fields such as agentEmail, agentPlatformId, and callerClientIp are not inferred from TurnContext; pass them explicitly through runWithA365Context() or the TurnContext options when you need those dimensions.

Exporter Modes

For batch export, provide tokenResolver in initA365Observability().

For per-request export, pass exportToken to runWithA365Context() and enable per-request export in the Microsoft SDK configuration or environment.

v0 Limits

v0 does not expose:

  • a separate Microsoft OutputScope span;
  • agent-to-agent HTTP trace propagation wrappers;
  • real-time threat protection or chat-history submission middleware.

Those remain additive adapter features if an Agent 365 deployment needs them.

Examples

Examples live in the repository under packages/agent-a365-observability/examples. They are monorepo-local reference files and are not shipped in the npm tarball.