Perplexity Sample Agent - Node.js

This sample demonstrates how to build an agent using Perplexity in Node.js with the Microsoft Agent 365 SDK. It covers:

  • Observability: End-to-end tracing, caching, and monitoring for agent applications
  • Notifications: Services and models for managing user notifications
  • Tools: Model Context Protocol tools for building advanced agent solutions
  • Hosting Patterns: Hosting with Microsoft 365 Agents SDK

This sample uses the Microsoft Agent 365 SDK for Node.js.

For comprehensive documentation and guidance on building agents with the Microsoft Agent 365 SDK, including how to add tooling, observability, and notifications, visit the Microsoft Agent 365 Developer Documentation.

Prerequisites

  • Node.js 18.x or higher
  • Microsoft Agent 365 SDK
  • Perplexity API credentials

Configuration

Observability export

src/index.ts imports src/otel.ts first. This sample uses @microsoft/agents-a365-observability@1.0.0; with Agent365ExporterOptions.useS2SEndpoint = true, exports post to /observabilityService/tenants/{tenant}/otlp/agents/{agent}/traces?api-version=1. Leave ENABLE_A365_OBSERVABILITY_PER_REQUEST_EXPORT unset or false because the 1.0.0 per-request mode still reads runWithExportToken, not the configured app-only resolver.

@opentelemetry/core is an explicit dependency because the 1.0.0 exporter imports it without declaring it; relying on incidental dependency hoisting can fail at startup.

When ENABLE_A365_OBSERVABILITY_EXPORTER=true, set AGENT365_OBS_TENANT_ID, AGENT365_OBS_AGENT_ID, AGENT365_OBS_BLUEPRINT_CLIENT_ID, and AGENT365_OBS_BLUEPRINT_CLIENT_SECRET from the template. AGENT365_OBS_AGENT_ID must be the actual agent instance client ID. The sample-local resolver uses blueprint credentials plus fmi_path to acquire T1, then the agent identity's client_credentials grant for OBS. It fails closed on delegated scp tokens, identity, tenant, audience, role, expiry, or response-shape mismatches. Business MCP, Graph, Power Platform, and OBO calls remain separate.

Single-instance limitation: this resolver exports for one statically configured agent instance and tenant (AGENT365_OBS_*). It needs its own copy of the blueprint secret and has no managed-identity option. Multi-instance or multi-tenant deployments should reuse the hosting connection per agent/tenant instead of sharing this static provider.

Sovereign clouds are not supported by this sample provider because the authority is hard-coded to login.microsoftonline.com. For AI Teammates, complete the Agent365.Observability.OtelWrite application-role step printed by a365 setup all --aiteammate; AI Teammate S2S without it has not been validated.

Working with User Identity

On every incoming message, the A365 platform populates activity.from with basic user information — always available with no API calls or token acquisition:

Field Description
activity.from.id Channel-specific user ID (e.g., 29:1AbcXyz... in Teams)
activity.from.name Display name as known to the channel
activity.from.aadObjectId Azure AD Object ID — use this to call Microsoft Graph

The sample logs these fields at the start of every message turn and injects the display name into the LLM system instructions for personalized responses.

Sending Multiple Messages in Teams

Agent365 agents can send multiple discrete messages in response to a single user prompt in Teams. This is achieved by calling sendActivity multiple times within a single turn.

Important: Streaming responses are not supported for agentic identities in Teams. The SDK detects agentic identity and buffers the stream into a single message. Use sendActivity directly to send immediate, discrete messages to the user.

The sample demonstrates this in the message activity handler (agent.ts):

// Message 1: immediate ack — reaches the user right away
await context.sendActivity('Got it — working on it…');

// ... LLM processing ...

// Message 2: the LLM response
await context.sendActivity(modelResponse);

Each sendActivity call produces a separate Teams message. You can call it as many times as needed to send progress updates, partial results, or a final answer.

Typing Indicators

The agent sends typing indicators in a loop every ~4 seconds to keep the ... animation alive while the LLM processes the request:

let typingInterval: ReturnType<typeof setInterval> | undefined;
const startTypingLoop = () => {
  typingInterval = setInterval(async () => {
    await context.sendActivity(Activity.fromObject({ type: ActivityTypes.Typing }));
  }, 4000);
};
const stopTypingLoop = () => { clearInterval(typingInterval); };

startTypingLoop();
try {
  // ... LLM processing ...
} finally {
  stopTypingLoop();
}

Note: Typing indicators are only visible in 1:1 chats and small group chats — not in channels.

Running the Agent

To set up and test this agent, refer to the Configure Agent Testing guide for complete instructions.

Support

For issues, questions, or feedback:

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Additional Resources

Trademarks

Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries. The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks. Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.

License

Copyright (c) Microsoft Corporation. All rights reserved.

Licensed under the MIT License - see the LICENSE file for details.