Autonomous Agent — Node.js Sample

This sample demonstrates a purely autonomous agent built with the Microsoft Agent 365 SDK for Node.js/TypeScript. It has no chat functionality — it runs entirely as a background service.

Every 60 seconds, the agent:

  1. Prompts Azure OpenAI to fetch trending GitHub repositories using a registered tool
  2. The model calls the get_trending_repositories tool, which queries the GitHub Search API
  3. The model summarizes the results into a readable digest
  4. The digest is logged to the console

All operations are manually instrumented with Agent 365 observability using the A365 Observability SDK tracing scopes (InvokeAgentScope, InferenceScope, ExecuteToolScope). This makes it a useful reference for instrumenting any non-interactive or custom agent loop.

For comprehensive documentation, visit the Microsoft Agent 365 Developer Documentation.

What This Sample Demonstrates

Pattern Where
Autonomous background service with LLM tool calling src/github-trending-service.ts
GitHub Search API tool with observability src/tools/github-trending-tool.ts
Azure OpenAI chat completions with function calling src/github-trending-service.ts
A365 observability with manual tracing scopes src/github-trending-service.ts, src/tools/github-trending-tool.ts
Microsoft OpenTelemetry distro with S2S exporter src/index.ts
3-hop FMI/FIC token flow for observability export src/observability-token-service.ts
Periodic heartbeat service src/heartbeat-service.ts

Prerequisites

  • Node.js 18 or higher
  • Azure CLI
  • Agent 365 CLI (install: dotnet tool install --global Microsoft.Agents.A365.DevTools.Cli --prerelease)
  • An Azure OpenAI resource with a deployed model (e.g., gpt-4o)
  • An Entra tenant with at minimum the Agent ID Developer role

Environment Configuration

Agent 365 Setup

  1. Log in to Azure: az login
  2. Provision the agent:
cd nodejs/autonomous/github-trending
a365 setup all --agent-name <your-agent-name>

Complete blueprint/identity provisioning and Agent 365 registration for the exact runtime instance, then copy the provisioned values into .env (see below). CLI versions may offer permission setup separately; an OBS grant is not a universal requirement. Eligible registered instances can use roleless app tokens on the public S2S OTLP route when service policy permits. Entra identity creation alone is not registration. Confirm the CLI permission choices rather than automatically granting Agent365.Observability.OtelWrite. 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.

The MSAL application-token flow does not require a client-side roles check. Its token is cached by agent/tenant only while the returned expiry is valid. For 401/403, check instance registration, token identity/audience and service policy; never substitute an OBO token or switch the exporter route.

Configuration

Copy .env.template to .env and fill in the values from a365 setup all output:

cp .env.template .env
Variable Set by Description
AZURE_OPENAI_ENDPOINT Manual Azure OpenAI resource endpoint
AZURE_OPENAI_API_KEY Manual Azure OpenAI API key
AZURE_OPENAI_DEPLOYMENT Manual Model deployment name (default: gpt-4o)
AGENT365_TENANT_ID CLI Entra tenant ID
AGENT365_AGENT_ID CLI Agent identity ID (separate from blueprint)
AGENT365_BLUEPRINT_ID CLI Blueprint app registration ID
AGENT365_CLIENT_ID CLI Blueprint app ID (same as blueprint ID)
AGENT365_CLIENT_SECRET CLI Blueprint client secret
AGENT365_AGENT_NAME CLI Display name shown in traces
AGENT365_AGENT_DESCRIPTION CLI Agent description shown in traces
AGENT365_USE_MANAGED_IDENTITY Manual true for production (MSI), false for local dev. Defaults to true when unset.
Variable Description Default
GITHUB_TRENDING_LANGUAGE Programming language filter typescript
GITHUB_TRENDING_MIN_STARS Minimum star count 5
GITHUB_TRENDING_MAX_RESULTS Number of repositories per digest 10
HEARTBEAT_INTERVAL_MS Polling interval in milliseconds 60000

The GitHub Search API is unauthenticated — no API key required (rate limit: 10 requests/minute).

Running the Agent Locally

Quick start (Azure OpenAI only)

You can run the agent with just Azure OpenAI credentials — no Agent 365 setup required. Create a minimal .env:

AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
AZURE_OPENAI_API_KEY=your-api-key
AZURE_OPENAI_DEPLOYMENT=gpt-4o
AGENT365_USE_MANAGED_IDENTITY=false
NODE_ENV=development

Then:

cd nodejs/autonomous/github-trending
npm install
npm run dev

The agent will skip the observability token service and log a warning:

Agent365 credentials not configured — skipping token service.
Run 'a365 setup all' to enable A365 observability export.

To enable full A365 observability, complete the Agent 365 Setup steps and fill in the remaining .env values.

Local development (with A365 observability)

Copy .env.template to .env and fill in all values from a365 setup all. The template sets AGENT365_USE_MANAGED_IDENTITY=false, which tells the token service to authenticate using the blueprint's client secret instead of Managed Identity.

cd nodejs/autonomous/github-trending
cp .env.template .env   # then fill in the values from a365 setup all
npm install
npm run dev

The agent starts on http://localhost:3979. Console output shows:

  • Observability token registration on startup
  • Trending digest immediately, then every 60 seconds
  • Heartbeat log every 60 seconds

Deploying the Agent

Build and run:

npm run build
npm start

Deploy to your hosting provider and ensure:

  1. Managed Identity is enabled on the hosting resource — the MSI must have a Federated Identity Credential (FIC) configured against the blueprint app
  2. All AGENT365_* environment variables are set (except AGENT365_CLIENT_SECRET, which is only needed if MSI is unavailable)

Observability Architecture

Tracing spans

Each autonomous cycle produces three nested spans:

InvokeAgentScope                        (root — wraps the entire cycle)
  |-- InferenceScope                    (child — wraps the LLM call)
  |-- ExecuteToolScope                  (child — wraps the GitHub API tool call)

Token flow — 3-hop FMI chain

The observability-token-service.ts background task acquires tokens using:

Local dev (client secret):
  Blueprint ClientSecret + fmi_path(agentId) → Entra token endpoint
      -> T1 token (targeted at Agent Identity)
      -> Agent Identity ConfidentialClient + T1 as assertion
      -> AcquireTokenForClient("api://9b975845-.../.default")
      -> Observability API token

Production (MSI):
  MSI -> ManagedIdentityCredential.getToken("api://AzureADTokenExchange")
      -> Blueprint ConfidentialClient + assertion + FMI path(agentId)
      -> T1 token (targeted at Agent Identity)
      -> Agent Identity ConfidentialClient + T1 as assertion
      -> Observability API token

Note: The local dev path uses a raw HTTP token request instead of MSAL because @azure/msal-node does not yet support the fmi_path parameter. The production MSI path uses MSAL with fmiPath via type assertion.

The token is refreshed every 50 minutes and cached in token-cache.ts.

For more details, see Agent observability — Microsoft Learn.

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.