Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 63 additions & 20 deletions compat/baseline/agents-hosting.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,12 @@ export const adaptiveCardsSearchParamsZodSchema: z.ZodObject<{
}>;

// @public
export class AgentApplication<TState extends TurnState> {
constructor(options?: Partial<AgentApplicationOptions<TState>>);
get adapter(): BaseAdapter;
get adaptiveCards(): AdaptiveCardsActions<TState>;
addRoute(selector: RouteSelector, handler: RouteHandler<TState>, isInvokeRoute?: boolean, rank?: number, authHandlers?: string[]): this;
export class AgentApplication<TState extends TurnState> {
constructor(options?: Partial<AgentApplicationOptions<TState>>);
get adapter(): BaseAdapter;
get adaptiveCards(): AdaptiveCardsActions<TState>;
get proactive(): ProactiveActions<TState>;
addRoute(selector: RouteSelector, handler: RouteHandler<TState>, isInvokeRoute?: boolean, rank?: number, authHandlers?: string[]): this;
// (undocumented)
protected readonly _afterTurn: ApplicationEventHandler<TState>[];
get authorization(): Authorization;
Expand Down Expand Up @@ -203,21 +204,63 @@ export class AgentApplicationBuilder<TState extends TurnState = TurnState> {
}

// @public
export interface AgentApplicationOptions<TState extends TurnState> {
adapter?: CloudAdapter;
adaptiveCardsOptions?: AdaptiveCardsOptions;
agentAppId?: string;
authorization?: AuthorizationOptions;
fileDownloaders?: InputFileDownloader<TState>[];
headerPropagation?: HeaderPropagationDefinition;
longRunningMessages: boolean;
normalizeMentions?: boolean;
removeRecipientMention?: boolean;
startTypingTimer: boolean;
storage?: Storage_2;
transcriptLogger?: TranscriptLogger;
turnStateFactory: () => TState;
}
export interface AgentApplicationOptions<TState extends TurnState> {
adapter?: CloudAdapter;
adaptiveCardsOptions?: AdaptiveCardsOptions;
agentAppId?: string;
authorization?: AuthorizationOptions;
fileDownloaders?: InputFileDownloader<TState>[];
headerPropagation?: HeaderPropagationDefinition;
longRunningMessages: boolean;
normalizeMentions?: boolean;
proactiveOptions?: ProactiveOptions;
removeRecipientMention?: boolean;
startTypingTimer: boolean;
storage?: Storage_2;
transcriptLogger?: TranscriptLogger;
turnStateFactory: () => TState;
}

// @public
export class ProactiveActions<TState> {
constructor(app: AgentApplication<TState>, options?: ProactiveOptions);
deleteReference(conversationId: string, channelId: string): Promise<void>;
getReference(conversationId: string, channelId: string): Promise<ProactiveReferenceRecord | undefined>;
saveReference(conversationId: string, channelId: string, identity: JwtPayload, reference: ConversationReference, ttlOverrideSeconds?: number): Promise<void>;
sendActivities(conversationId: string, channelId: string, activities: (Activity | Partial<Activity>)[]): Promise<ProactiveSendResult>;
sendToReference(identity: JwtPayload, reference: ConversationReference, activities: (Activity | Partial<Activity>)[]): Promise<ProactiveSendResult>;
}

// @public
export interface ProactiveHttpOptions {
prefix?: string;
}

// @public
export interface ProactiveOptions {
autoPersistReferences?: boolean;
keyFactory?: (channelId: string, conversationId: string) => string | Promise<string>;
referenceTtlSeconds?: number;
storage?: Storage_2;
}

// @public
export interface ProactiveReferenceRecord extends StoreItem {
channelId: string;
conversationId: string;
expiresUtc?: string;
identity: JwtPayload;
reference: ConversationReference;
updatedUtc: string;
}

// @public
export interface ProactiveSendResult {
activityIds: string[];
}

// @public
export function registerProactiveRoutes<TState>(app: Application, agent: AgentApplication<TState>, options?: ProactiveHttpOptions): void;

// @public
export const AgentCallbackHandlerKey = "agentCallbackHandler";
Expand Down
71 changes: 54 additions & 17 deletions packages/agents-hosting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,57 @@ 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))
})

```
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))
})

```

## Proactive messaging

`AgentApplication.proactive` simplifies persisting conversation references and sending activities outside the normal turn flow.

```ts
import { Activity, AgentApplication, MemoryStorage } from '@microsoft/agents-hosting'

const app = new AgentApplication({
storage: new MemoryStorage(),
proactiveOptions: { autoPersistReferences: true }
})

app.onMessage(async (context) => {
await context.sendActivity('Thanks, I will keep you posted!')
})

await app.proactive.sendActivities(
'conversation-id',
'msteams',
[Activity.fromObject({ type: 'message', text: 'Here is a proactive update.' })]
)
```

To integrate with external schedulers or services, register the optional HTTP endpoints:

```ts
import express from 'express'
import { registerProactiveRoutes } from '@microsoft/agents-hosting'

const server = express()
server.use(express.json())

registerProactiveRoutes(server, app)
```

The extension adds `/api/sendactivity` and `/api/sendtoreference` endpoints that call the proactive helper internally.
12 changes: 12 additions & 0 deletions packages/agents-hosting/src/app/agentApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ResourceResponse } from '../connector-client'
import { debug } from '@microsoft/agents-activity/logger'
import { TurnContext } from '../turnContext'
import { AdaptiveCardsActions } from './adaptiveCards'
import { ProactiveActions } from './proactive'
import { AgentApplicationOptions } from './agentApplicationOptions'
import { ConversationUpdateEvents } from './conversationUpdateEvents'
import { AgentExtension } from './extensions'
Expand Down Expand Up @@ -79,6 +80,7 @@ export class AgentApplication<TState extends TurnState> {
private _typingTimer: NodeJS.Timeout | undefined
protected readonly _extensions: AgentExtension<TState>[] = []
private readonly _adaptiveCards: AdaptiveCardsActions<TState>
private readonly _proactive: ProactiveActions<TState>

/**
* Creates a new instance of AgentApplication.
Expand Down Expand Up @@ -118,6 +120,7 @@ export class AgentApplication<TState extends TurnState> {
}

this._adaptiveCards = new AdaptiveCardsActions<TState>(this)
this._proactive = new ProactiveActions<TState>(this, this._options.proactiveOptions)

if (this._options.adapter) {
this._adapter = this._options.adapter
Expand Down Expand Up @@ -195,6 +198,15 @@ export class AgentApplication<TState extends TurnState> {
return this._adaptiveCards
}

/**
* Gets the proactive messaging helper for the application.
*
* @returns The proactive actions instance.
*/
public get proactive (): ProactiveActions<TState> {
return this._proactive
}

/**
* Sets an error handler for the application.
*
Expand Down
8 changes: 8 additions & 0 deletions packages/agents-hosting/src/app/agentApplicationOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { CloudAdapter } from '../cloudAdapter'
import { Storage } from '../storage'
import { TranscriptLogger } from '../transcript'
import { AdaptiveCardsOptions } from './adaptiveCards'
import { ProactiveOptions } from './proactive'
import { InputFileDownloader } from './inputFileDownloader'
import { TurnState } from './turnState'
import { HeaderPropagationDefinition } from '../headerPropagation'
Expand Down Expand Up @@ -107,6 +108,13 @@ export interface AgentApplicationOptions<TState extends TurnState> {
*/
adaptiveCardsOptions?: AdaptiveCardsOptions;

/**
* Configuration for proactive messaging support.
*
* @default undefined (no proactive helper configured)
*/
proactiveOptions?: ProactiveOptions;

/**
* Whether to automatically remove mentions of the bot's name from incoming messages.
* When enabled, if a user mentions the bot by name (e.g., "@BotName hello"), the mention
Expand Down
1 change: 1 addition & 0 deletions packages/agents-hosting/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export * from './inputFileDownloader'
export * from './appMemory'
export * from './extensions'
export * from './adaptiveCards'
export * from './proactive'
export * from './streaming/streamingResponse'
export * from './streaming/citation'
3 changes: 3 additions & 0 deletions packages/agents-hosting/src/app/proactive/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './proactiveActions'
export * from './proactiveTypes'
export * from './proactiveServiceExtensions'
Loading