@microsoft/agents-activity

TypeScript types and Zod validators implementing Microsoft's Activity Protocol for building conversational agents.

Library
npm
v1.8.1
87stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
77/100Good
Development Activity96
Maintenance100
Community48
Maturity44
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture78
Code Quality88
Innovation68
Learning Curve85

@microsoft/agents-activity implements the Activity Protocol Specification used throughout the Microsoft 365 Agent SDK — the message envelope exchanged between agents and channels such as Teams, Copilot Studio, and Webchat. It is the direct successor to the legacy botframework-schema package, giving every field a matching Zod schema so a single call validates untrusted channel payloads and produces a fully-typed Activity instance.

Beyond the base protocol shape, the package adds composite channel:subChannel channel IDs (e.g. m365:copilot), conversation-reference helpers for replying to or resuming a conversation, mention-tag normalization, group-only “targeted activity” treatments, and agentic-identity accessors for agent-to-agent and delegated scenarios. It has no dependencies beyond zod and is consumed directly by sibling packages like @microsoft/agents-hosting.

What You Get

  • A fully-typed Activity class covering the entire Activity Protocol surface — messages, invokes, conversation updates, event activities, adaptive card invokes
  • Zod schemas for every nested type (attachments, entities, actions, conversation references) with passthrough support for channel-specific extensions
  • Conversation reference and reply-target helpers for building and resuming conversations across group and 1:1 channels
  • Mention normalization, targeted-activity, and agentic-identity utility methods shared across the wider M365 Agents SDK

Common Use Cases

  • Defining and validating the wire format for messages exchanged between agents and channels (Teams, Webchat, Copilot Studio)
  • Migrating existing Bot Framework (botframework-schema/botbuilder) code onto the M365 Agents SDK
  • Building custom channel adapters that need composite channel/sub-channel routing
  • Normalizing and stripping <at> mention tags before rendering agent text to end users

Under The Hood

Architecture The package is a single flat module (packages/agents-activity) with no internal layers beyond domain folders (action/, attachment/, conversation/, entity/, invoke/), each pairing a TypeScript interface with its matching Zod schema (e.g. conversationReference.ts exports both ConversationReference and conversationReferenceZodSchema). The Activity class in src/activity.ts is the composition root: its constructor takes only a type, the fromObject/fromJson static factories run the whole tree through activityZodSchema.passthrough().parse() before assigning onto a real class instance, and getters/setters (channelId, channelIdSubChannel) reach into a companion entity/productInfo.ts module to synthesize or read a ProductInfo entity for composite channel IDs. There is no dependency injection or plugin system — the abstraction to protect is the paired type/schema pattern; changing an interface without updating its matching Zod schema (or vice versa) would silently desync compile-time types from runtime validation. index.ts is a flat barrel export consumed directly by sibling packages such as agents-hosting.

Tech Stack TypeScript is compiled via a shared root tsconfig.build.json (target es2019, module node16, strict: true, composite: true project references) to CJS output in dist/src, with separate build:esm and build:browser steps run from the monorepo root. The only runtime dependency is zod, pinned via a workspace catalog; a browser field swaps in src/browser/crypto.ts for Node’s crypto.randomUUID in non-Node bundles. Linting uses neostandard’s ESLint flat config plus a repo-authored custom rule (no-terminal-test-cast) and a no-restricted-syntax rule forbidding raw throw new Error() in favor of ExceptionHelper.generateException. Tests run on Node’s built-in node:test runner via tsx, with no separate test framework. The package ships inside an npm-workspaces monorepo (packages/*) validated by a custom repo:doctor script that checks build references, package exports, and dependency catalogs.

Code Quality Tests mirror src/ under test/ (e.g. test/activity/activity.test.ts, test/conversation/channelAccount.test.ts) using Node’s native assert with node:test’s describe/it, covering constructor validation, Zod parse failures, mention stripping, and targeted-activity treatment logic across every domain folder. Error handling is explicit and centralized: every thrown error routes through ExceptionHelper.generateException(ErrorClass, ErrorsEnum, ...) against a stable Errors enum (InvalidChannelIdFormat, PrimaryChannelNotSet, etc.) instead of ad hoc messages, enforced repo-wide by a custom ESLint rule. Naming is consistent camelCase with JSDoc on every public member, and typing is strict with any reserved for deliberate passthrough fields like channelData. CI runs repository-structure validation, lint, unused-dependency checks (knip), a full build, and the test suite on every pull request, plus nightly builds and dedicated Teams-API drift-detection workflows.

API Design The core design bet is pairing every exported TypeScript type 1:1 with a Zod schema, so one .parse() call gives both compile-time typing and runtime validation of untrusted channel payloads — with .passthrough() so channel-specific extension fields survive round-tripping instead of being silently dropped. The composite channel:subChannel scheme (e.g. m365:copilot) and its getConversationReference({ forceBaseChannel }) escape hatch, along with agentic-identity accessors (isAgenticRequest, getAgenticTenantId), extend the original Bot Framework Activity shape to multi-channel and agent-to-agent scenarios. Developer experience is straightforward: a single import surface, consistent JSDoc, and no boilerplate beyond new Activity(type) or Activity.fromObject(json).

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search