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

@microsoft/agents-hosting

v1.9.1

Published

Microsoft 365 Agents SDK for JavaScript

Readme

@microsoft/agents-hosting

Overview

The @microsoft/agents-hosting package provides the necessary tools and components to create and host Microsoft Agents. This package includes a compatible API to migrate a bot using botbuilder from the BotFramework SDK.

Installation

To install the package:

npm install @microsoft/agents-hosting

Hosting integration APIs

To make hosting an agent independent of any single web framework, this package exposes framework-agnostic primitives that the @microsoft/agents-hosting-express and @microsoft/agents-hosting-fastify packages build on:

  • createCloudAdapter(agent, authConfig, options?) — returns { adapter, headerPropagation } for processing incoming activities. It preserves an AgentApplication's existing adapter; authConfig is used only when creating an adapter. Use options.configurationContext to scope preloaded configuration to this host. Use this from any web framework.
  • CloudAdapterResult — return type of createCloudAdapter.
  • createAgentResponseHandler(adapter, agent, conversationState) — framework-agnostic handler (req, res, params) => Promise<void> for the authenticated SDK-specific Activity callback route.
  • AgentResponseHandler, AgentResponseHandlerParams, AGENT_RESPONSE_ROUTE_PATH — supporting types and the canonical route path.
  • WebResponse, NextFunction, WebRequestParamsCarrier — minimal structural interfaces (no Express/Fastify imports) used by the cross-framework helpers above.

Most consumers should keep using startServer/createAgentRequestHandler from the Express or Fastify packages; reach for these APIs when adapting another framework.

This Activity callback flow is used for SDK-specific Activity-protocol delegation.

The Activity callback handler authenticates requests once through the supplied CloudAdapter. That boundary validates the token for any configured host connection; the handler then verifies that the caller application matches the delegated agent recorded for that conversation. Existing route-level authorizeJWT middleware is redundant but remains compatible. On configured or production hosts, missing, invalid, expired, or wrong-audience tokens return 401. An authenticated caller that does not match the delegated agent, or missing, malformed, or pre-upgrade delegated state, returns 403. Anonymous callbacks are supported only for unconfigured development hosts outside production and emit a registration warning because peer ownership cannot be verified. Pre-upgrade conversations must be restarted.

Pluggable configuration sources

Existing environment variables and direct runtime options continue to work without changes. Additional asynchronous sources can be loaded into an immutable host-scoped context and then consumed synchronously by auth configuration, CloudAdapterOptions, outbound host validation, and AgentApplication user authorization:

import {
  AttachmentDownloader,
  CloudAdapter,
  createConfigurationContext,
  createOutboundHostValidator,
  ConfigurationSource,
} from '@microsoft/agents-hosting'

const source: ConfigurationSource = {
  name: 'central-configuration',
  async load () {
    return {
      format: 'document',
      value: {
        cloudAdapterOptions: {
          validateServiceUrl: true
        },
        outboundHostValidator: {
          enabled: true,
          hosts: ['api.contoso.com']
        }
      }
    }
  }
}

const configurationContext = await createConfigurationContext([{
  source,
  mode: 'overrideEnvironment'
}])

const adapter = new CloudAdapter(
  undefined,
  undefined,
  undefined,
  { configurationContext }
)

// Reuse the same policy for code-level outbound consumers such as attachment
// downloaders.
const outboundPolicy = createOutboundHostValidator({ configurationContext })
const downloader = new AttachmentDownloader('inputFiles', outboundPolicy)

For an explicitly selected JSON file, use the built-in file source:

import {
  createConfigurationContext,
  createJsonFileConfigurationSource
} from '@microsoft/agents-hosting'

const configurationContext = await createConfigurationContext([{
  source: createJsonFileConfigurationSource('config.DEVELOPMENT.json'),
  mode: 'overrideEnvironment'
}])

The helper loads strict JSON using the hierarchical document shape. It does not discover files, select environment-specific names, parse command-line options, or choose precedence. The application owns those policies and supplies the source mode. Missing files, malformed JSON, and non-object document roots fail loading without including file contents in diagnostics.

Context creation is atomic: if a source fails, no partial values are applied. Create separate contexts for independently configured agents in one process. Pass the same context to each agent's CloudAdapter and AgentApplication. Existing applications may instead call preloadConfigurationSources once before constructing consumers; that API is the compatibility wrapper over the default process context.

Load the default context before constructing any configuration consumer. Default-context loading is atomic and retryable after failure, but a successful load can occur only once and cannot run concurrently. Constructing a consumer first consumes an empty default snapshot and prevents later preload. To adopt updated or rotated values, create a new immutable context and reconstruct its consumers; existing contexts and consumers are not mutated.

Every source must select an explicit mode:

  • fallback: below Bot Framework compatibility variables and supported modern __ environment configuration.
  • overrideEnvironment: above environment configuration and below direct runtime options.
  • enforce: above direct runtime options.

Sources in the same mode are applied in registration order, with later values winning. enforce can override values supplied directly by application code and should be reserved for deliberate central policy enforcement.

Within the environment band, a modern Connections__* registry replaces flat or prefixed Bot Framework authentication variables; the two representations are not merged property by property. When no modern registry exists, the legacy flat or prefixed variables remain supported. When a modern environment registry has no ConnectionsMap__* entries, the environment auth loader preserves backward compatibility by creating a wildcard/default route for the first connection; connection insertion order determines the default only in that case. External sources may omit connectionsMap when they define exactly one connection, which is treated as the wildcard/default. External sources that define multiple connections must provide an explicit wildcard/default route.

Supported canonical path families are:

  • connections.<id>.settings.<property>
  • connectionsMap.<index>.serviceUrl
  • connectionsMap.<index>.audience
  • connectionsMap.<index>.connection
  • cloudAdapterOptions.<property>
  • outboundHostValidator.<property>
  • agentApplication.userAuthorization.handlers.<id>.settings.<property>

Sources return either { format: 'canonical', values } for canonical string paths or { format: 'document', value } for hierarchical typed JSON. Existing sources that return a bare canonical record remain supported for backward compatibility; new sources should use the explicit tagged form. Canonical paths use current property names only, except for the retained WIDAssertionFile compatibility spelling (prefer federatedTokenFile). Schema-shaped __ environment variables are also a permanent first-class input and bind to the same hierarchy. Bot Framework-era MicrosoftApp*, prefixed connection, and <handlerId>_* aliases remain supported through an isolated compatibility adapter, but are not valid external-source paths. Invalid paths or values fail loading without including the supplied value in diagnostics.

The provider-neutral hierarchical document shape is defined by agents-configuration.schema.json.

Example Usage based on the AgentApplication object

import { AgentApplication, MemoryStorage, TurnContext, TurnState } from '@microsoft/agents-hosting'

const echo = new AgentApplication<TurnState>({ storage: new MemoryStorage() })
echo.onConversationUpdate('membersAdded', async (context: TurnContext) => {
  await context.sendActivity('Welcome to the Echo sample, send a message to see the echo feature in action.')
})
echo.onActivity('message', async (context: TurnContext, state: TurnState) => {
  let counter: number = state.getValue('conversation.counter') || 0
  await context.sendActivity(`[${counter++}]You said: ${context.activity.text}`)
  state.setValue('conversation.counter', counter)
})

Storage providers

Public storage options accept StorageProvider, which is Storage | StorageV2. Providers can implement either contract. Custom V2 providers extend StorageV2, so hosting can identify the structured contract with instanceof. Hosting adapts a legacy Storage provider for default upsert operations. The adapter cannot support create-only, replace, or version conditions. Built-in V1 and V2 providers have separately named classes, avoiding overloaded JavaScript methods while preserving every legacy constructor and return type:

const legacyStorage = new MemoryStorage()
const storageV2 = new MemoryStorageV2()
const fileStorageV2 = new FileStorageV2('./data')

V2 calls return keyed operation results. Read values are at results[key].value; inspect status and version for operation outcomes.

Example Usage based on bot framework Activity Handler

Create an Echo bot using the ActivityHandler

// myHandler.ts
import { ActivityHandler, MessageFactory } from '@microsoft/agents-hosting'

export class MyHandler extends ActivityHandler {
  constructor () {
    super()
    this.onMessage(async (context, next) => {
      const replyText = `Agent: ${context.activity.text}`
      await context.sendActivity(MessageFactory.text(replyText))
      await next()
    })
  }
}

Host the bot with express

// index.ts
import express, { Response } from 'express'
import { Request, CloudAdapter, authorizeJWT, AuthConfiguration, loadAuthConfigFromEnv } from '@microsoft/agents-hosting'
import { EchoBot } from './myHandler'

const authConfig: AuthConfiguration = loadAuthConfigFromEnv()

const adapter = new CloudAdapter(authConfig)
const myHandler = new MyHandler()

const app = express()

app.use(express.json())
app.use(authorizeJWT(authConfig))

app.post('/api/messages', async (req: Request, res: Response) => {
  await adapter.process(req, res, async (context) => await myHandler.run(context))
})

Inbound token issuer validation

Inbound JWT signature, audience, lifetime, and tenant-claim consistency checks are always applied. Issuer allow-list validation is opt-in because AgentID blueprint identities can use runtime-selected tenant issuers that are not known when the host configuration is created.

Enable issuer validation only when every accepted issuer is represented by the connection's configured tenant or issuers list:

validateIssuer=true

# Latest connection configuration format
Connections__serviceConnection__Settings__ValidateIssuer=true

Accepted boolean values are true, false, 1, and 0 (case-insensitive, with surrounding whitespace ignored). Any other non-empty value causes configuration loading to fail with a structured error that identifies the configuration source and accepted values.

Outbound request host validation

OutboundHostValidator provides an opt-in allowlist for server-side requests made to activity service URLs and attachment URLs. Enforcement is disabled by default. It can be configured with environment variables:

OutboundHostValidator__Enabled=true
OutboundHostValidator__IncludeDefaultMicrosoftHosts=true
OutboundHostValidator__Hosts=contoso.com,fabrikam.com

Indexed host variables such as OutboundHostValidator__Hosts__0=contoso.com are also supported. A host entry matches both the exact host and its subdomains, and is normalized (scheme/port/path stripped; a leading *. is accepted and ignored).

When enforcement is enabled, CloudAdapter rejects inbound activities whose serviceUrl host is not allowlisted, and it also rejects serviceurl claim mismatches (equivalent to CloudAdapterOptions.validateServiceUrl=true).

For explicit configuration, reuse the same immutable policy in the adapter and attachment downloaders:

import {
  AgentApplication,
  AttachmentDownloader,
  CloudAdapter,
  OutboundHostValidator
} from '@microsoft/agents-hosting'

const outboundHostValidator = new OutboundHostValidator({
  enabled: true,
  hosts: ['contoso.com']
})

const adapter = new CloudAdapter(undefined, undefined, undefined, undefined, outboundHostValidator)

const agent = new AgentApplication({
  adapter,
  fileDownloaders: [new AttachmentDownloader('inputFiles', outboundHostValidator)]
})

The validator checks the URL supplied to the downloader. Redirects retain native fetch behavior.