Full Code of microsoft/teams-ai for AI

main f393932802d7 cached
318 files
858.9 KB
207.5k tokens
116 symbols
1 requests
Download .txt
Showing preview only (958K chars total). Download the full file or copy to clipboard to get everything.
Repository: microsoft/teams-ai
Branch: main
Commit: f393932802d7
Files: 318
Total size: 858.9 KB

Directory structure:
gitextract_6wy_q17s/

├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── deploy-teams-docs.yml
├── .gitignore
├── .gitmodules
├── .prettierignore
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── package.json
├── packages/
│   └── README.md
├── prettier.config.js
├── teams.md/
│   ├── .gitattributes
│   ├── .gitignore
│   ├── LANGUAGE-INCLUDE.md
│   ├── README.md
│   ├── docs/
│   │   └── main/
│   │       ├── developer-tools/
│   │       │   ├── README.md
│   │       │   ├── _category_.json
│   │       │   ├── cli.md
│   │       │   └── devtools/
│   │       │       ├── README.md
│   │       │       ├── cards.md
│   │       │       ├── chat.md
│   │       │       └── inspect.md
│   │       ├── privacy.md
│   │       ├── teams/
│   │       │   ├── README.md
│   │       │   ├── _category_.json
│   │       │   ├── app-authentication/
│   │       │   │   ├── README.mdx
│   │       │   │   ├── _category_.json
│   │       │   │   ├── client-secret.md
│   │       │   │   ├── federated-identity-credentials.md
│   │       │   │   ├── troubleshooting.md
│   │       │   │   └── user-managed-identity.md
│   │       │   ├── configuration/
│   │       │   │   ├── README.md
│   │       │   │   ├── _category_.json
│   │       │   │   ├── agents-toolkit.md
│   │       │   │   └── manual-configuration.mdx
│   │       │   ├── core-concepts.md
│   │       │   ├── enabling-in-copilot.md
│   │       │   ├── manifest.md
│   │       │   └── user-authentication/
│   │       │       ├── README.md
│   │       │       ├── _category_.json
│   │       │       ├── sso-setup.mdx
│   │       │       └── troubleshooting-sso.mdx
│   │       ├── welcome.mdx
│   │       └── why.md
│   ├── docusaurus.config.ts
│   ├── i18n/
│   │   └── en/
│   │       ├── code.json
│   │       ├── docusaurus-plugin-content-docs/
│   │       │   └── current.json
│   │       ├── docusaurus-plugin-content-docs-csharp/
│   │       │   └── current.json
│   │       ├── docusaurus-plugin-content-docs-typescript/
│   │       │   └── current.json
│   │       └── docusaurus-theme-classic/
│   │           ├── footer.json
│   │           └── navbar.json
│   ├── package.json
│   ├── scripts/
│   │   ├── generate-language-docs.ts
│   │   ├── generate-llms-txt.ts
│   │   └── lib/
│   │       ├── content-processor.ts
│   │       ├── file-collector.ts
│   │       └── frontmatter-parser.ts
│   ├── sidebars.ts
│   ├── src/
│   │   ├── components/
│   │   │   ├── FileCodeBlock.tsx
│   │   │   ├── LangLink.tsx
│   │   │   ├── Language.tsx
│   │   │   ├── LanguageBanner.tsx
│   │   │   ├── LanguageDropdown.tsx
│   │   │   └── include/
│   │   │       ├── essentials/
│   │   │       │   ├── api/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── app-authentication/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── csharp.incl.md
│   │   │       │   ├── graph/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── on-activity/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── on-event/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── python.incl.md
│   │   │       │   ├── sending-messages/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── proactive-messaging/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   └── typescript.incl.md
│   │   │       ├── getting-started/
│   │   │       │   ├── _LLMs/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── code-basics/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── csharp.incl.md
│   │   │       │   ├── python.incl.md
│   │   │       │   ├── quickstart/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── running-in-teams/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   └── typescript.incl.md
│   │   │       ├── in-depth-guides/
│   │   │       │   ├── adaptive-cards/
│   │   │       │   │   ├── building-adaptive-cards/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── executing-actions/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── ai/
│   │   │       │   │   ├── a2a/
│   │   │       │   │   │   ├── a2a-client/
│   │   │       │   │   │   │   ├── python.incl.md
│   │   │       │   │   │   │   └── typescript.incl.md
│   │   │       │   │   │   ├── a2a-server/
│   │   │       │   │   │   │   ├── python.incl.md
│   │   │       │   │   │   │   └── typescript.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── best-practices/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── chat/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── function-calling/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── keeping-state/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── mcp/
│   │   │       │   │   │   ├── mcp-client/
│   │   │       │   │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   │   ├── python.incl.md
│   │   │       │   │   │   │   └── typescript.incl.md
│   │   │       │   │   │   └── mcp-server/
│   │   │       │   │   │       ├── csharp.incl.md
│   │   │       │   │   │       ├── python.incl.md
│   │   │       │   │   │       └── typescript.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   ├── setup-and-prereqs/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── csharp.incl.md
│   │   │       │   ├── dialogs/
│   │   │       │   │   ├── creating-dialogs/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── handling-dialog-submissions/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── handling-multi-step-forms/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── feedback/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── meeting-events/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── message-extensions/
│   │   │       │   │   ├── action-commands/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── link-unfurling/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── search-commands/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── settings/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── observability/
│   │   │       │   │   ├── logging/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── middleware/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── python.incl.md
│   │   │       │   ├── server/
│   │   │       │   │   ├── http-server/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── static-pages/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── tabs/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── functions/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── typescript.incl.md
│   │   │       │   └── user-authentication/
│   │   │       │       ├── csharp.incl.md
│   │   │       │       ├── python.incl.md
│   │   │       │       └── typescript.incl.md
│   │   │       └── migrations/
│   │   │           ├── botbuilder/
│   │   │           │   ├── integration/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   ├── proactive-activities/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   ├── sending-activities/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   ├── the-api-client/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   └── user-authentication/
│   │   │           │       ├── csharp.incl.md
│   │   │           │       ├── python.incl.md
│   │   │           │       └── typescript.incl.md
│   │   │           ├── slack-bolt/
│   │   │           │   └── typescript.incl.md
│   │   │           ├── v1/
│   │   │           │   ├── python.incl.md
│   │   │           │   └── typescript.incl.md
│   │   │           └── v2-previews/
│   │   │               └── typescript.incl.md
│   │   ├── constants/
│   │   │   └── languages.ts
│   │   ├── css/
│   │   │   ├── code-blocks.css
│   │   │   └── custom.css
│   │   ├── hooks/
│   │   │   └── useLanguagePreference.tsx
│   │   ├── pages/
│   │   │   ├── csharp.tsx
│   │   │   ├── index.module.css
│   │   │   ├── index.tsx
│   │   │   ├── python.tsx
│   │   │   ├── templates/
│   │   │   │   ├── essentials/
│   │   │   │   │   ├── README.mdx
│   │   │   │   │   ├── _category_.json
│   │   │   │   │   ├── api.mdx
│   │   │   │   │   ├── app-authentication.mdx
│   │   │   │   │   ├── app-basics.mdx
│   │   │   │   │   ├── graph.mdx
│   │   │   │   │   ├── on-activity/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   └── activity-ref.mdx
│   │   │   │   │   ├── on-event.mdx
│   │   │   │   │   └── sending-messages/
│   │   │   │   │       ├── README.mdx
│   │   │   │   │       ├── _category_.json
│   │   │   │   │       └── proactive-messaging.mdx
│   │   │   │   ├── getting-started/
│   │   │   │   │   ├── README.mdx
│   │   │   │   │   ├── _LLMs.mdx
│   │   │   │   │   ├── _category_.json
│   │   │   │   │   ├── code-basics.mdx
│   │   │   │   │   ├── quickstart.mdx
│   │   │   │   │   └── running-in-teams/
│   │   │   │   │       ├── README.mdx
│   │   │   │   │       └── _category_.json
│   │   │   │   ├── in-depth-guides/
│   │   │   │   │   ├── README.mdx
│   │   │   │   │   ├── _category_.json
│   │   │   │   │   ├── adaptive-cards/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── building-adaptive-cards.mdx
│   │   │   │   │   │   └── executing-actions.mdx
│   │   │   │   │   ├── ai/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── a2a/
│   │   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   │   ├── a2a-client.mdx
│   │   │   │   │   │   │   └── a2a-server.mdx
│   │   │   │   │   │   ├── best-practices.mdx
│   │   │   │   │   │   ├── chat.mdx
│   │   │   │   │   │   ├── function-calling.mdx
│   │   │   │   │   │   ├── keeping-state.mdx
│   │   │   │   │   │   ├── mcp/
│   │   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   │   ├── mcp-client.mdx
│   │   │   │   │   │   │   └── mcp-server.mdx
│   │   │   │   │   │   └── setup-and-prereqs.mdx
│   │   │   │   │   ├── dialogs/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── creating-dialogs.mdx
│   │   │   │   │   │   ├── handling-dialog-submissions.mdx
│   │   │   │   │   │   └── handling-multi-step-forms.mdx
│   │   │   │   │   ├── feedback.mdx
│   │   │   │   │   ├── meeting-events.mdx
│   │   │   │   │   ├── message-extensions/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── action-commands.mdx
│   │   │   │   │   │   ├── link-unfurling.mdx
│   │   │   │   │   │   ├── search-commands.mdx
│   │   │   │   │   │   └── settings.mdx
│   │   │   │   │   ├── observability/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── logging.mdx
│   │   │   │   │   │   └── middleware.mdx
│   │   │   │   │   ├── server/
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── http-server.mdx
│   │   │   │   │   │   └── static-pages.mdx
│   │   │   │   │   ├── tabs/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── app-options.mdx
│   │   │   │   │   │   ├── functions/
│   │   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   │   └── function-calling.mdx
│   │   │   │   │   │   ├── getting-started.mdx
│   │   │   │   │   │   ├── graph.mdx
│   │   │   │   │   │   └── using-the-app.mdx
│   │   │   │   │   └── user-authentication.mdx
│   │   │   │   └── migrations/
│   │   │   │       ├── README.mdx
│   │   │   │       ├── _category_.json
│   │   │   │       ├── botbuilder/
│   │   │   │       │   ├── README.mdx
│   │   │   │       │   ├── _category_.json
│   │   │   │       │   ├── integration.mdx
│   │   │   │       │   ├── proactive-activities.mdx
│   │   │   │       │   ├── sending-activities.mdx
│   │   │   │       │   ├── the-api-client.mdx
│   │   │   │       │   └── user-authentication.mdx
│   │   │   │       ├── slack-bolt.mdx
│   │   │   │       ├── v1.mdx
│   │   │   │       └── v2-previews.mdx
│   │   │   └── typescript.tsx
│   │   ├── scripts/
│   │   │   └── scaffold.js
│   │   ├── theme/
│   │   │   ├── DocSidebarItems/
│   │   │   │   └── index.tsx
│   │   │   ├── Navbar/
│   │   │   │   └── Content/
│   │   │   │       └── index.tsx
│   │   │   ├── PaginatorNavLink/
│   │   │   │   └── index.tsx
│   │   │   └── Root.tsx
│   │   └── utils/
│   │       ├── languageUtils.ts
│   │       ├── normalizePath.ts
│   │       ├── pageAvailability.ts
│   │       └── readFileUtf8Normalized.ts
│   ├── static/
│   │   ├── .nojekyll
│   │   ├── llms_docs/
│   │   │   └── llms.txt
│   │   ├── missing-pages.json
│   │   └── scripts/
│   │       └── clarity.js
│   └── tsconfig.json
└── turbo.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  pull_request:
      branches:
        - main
      paths:
        - 'teams.md/**'

jobs:
  build-teams-md:
    name: Build teams.md
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - name: Install dependencies (teams.md)
        run: npm ci
        working-directory: teams.md

      - name: Clear build artifacts
        working-directory: teams.md
        run: npm run clear

      - name: Build (teams.md)
        env:
          NODE_ENV: production
        run: npm run build
        working-directory: teams.md


================================================
FILE: .github/workflows/deploy-teams-docs.yml
================================================
name: Deploy-Teams-Docs
on:
  workflow_dispatch:
  push:
    branches:
      - main
    paths:
      - 'teams.md/**'
      - .github/workflows/deploy-teams-docs.yml

jobs:
  deploy:
    environment:
      name: github-pages
    runs-on: ubuntu-latest
    permissions:
      contents: write # To push a branch
      pages: write
      id-token: write

    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22.x'

      - name: Install dependencies
        working-directory: teams.md
        run: npm install

      - name: Clear build artifacts
        working-directory: teams.md
        run: npm run clear

      - name: Generate language docs
        working-directory: teams.md
        env:
          NODE_ENV: production
        run: npm run generate:docs

      - name: Generate llms.txt files
        working-directory: teams.md
        run: npm run generate:llms

      - name: Build static site
        working-directory: teams.md
        run: npm run build

      - name: Setup GitHub Pages
        uses: actions/configure-pages@v4

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: teams.md/build

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# Dependencies
node_modules
.pnp
.pnp.js

# Local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Testing
coverage

# Turbo
.turbo

# Vercel
.vercel

# Build Outputs
.next/
out/
build
dist

# Generated documentation files
teams.md/docs/main/typescript/
teams.md/docs/main/csharp/
teams.md/docs/main/python/


# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Misc
.DS_Store
*.pem
.specstory


================================================
FILE: .gitmodules
================================================


================================================
FILE: .prettierignore
================================================
dist
node_modules
coverage


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": ["streetsidesoftware.code-spell-checker"]
}


================================================
FILE: .vscode/settings.json
================================================
{
  "cSpell.words": [
    "botframework",
    "devtunnels",
    "Entra",
    "mdbook"
  ]
}


================================================
FILE: CONTRIBUTING.md
================================================
# Instructions for Contributing Code

Teams SDK is a mono-repo that hosts GitHub submodules to other repos that contain code by language. The submodules in this repository uses the latest commit from those submodules. To make changes to Teams SDK Typescript, C#, Python, please use the following repos:

- [Teams.ts](https://github.com/microsoft/teams.ts)
- [Teams.net](https://github.com/microsoft/teams.net)
- [Teams.py](https://github.com/microsoft/teams.py)

Please note that as of August 2023, signed commits are required for all contributions to this project. For more information on how to set up, see the [GitHub Authentication verify commit signature](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) documentation.

## Contributing bug fixes and features

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](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

Microsoft Teams is currently accepting contributions in the form of bug fixes and new
features. Any submission must have an issue tracking it in the issue tracker that has
been approved by the Teams SDK team. Your pull request should include a link to
the bug that you are fixing. If you've submitted a PR for a bug, please post a
comment in the bug to avoid duplication of effort.

## Legal

If your contribution is more than 15 lines of code, you will need to complete a Contributor
License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission
to use the submitted change according to the terms of the project's license, and that the work
being submitted is under appropriate copyright.

Please submit a Contributor License Agreement (CLA) before submitting a pull request.
You may visit https://cla.azure.com to sign digitally.

## Contributing guide

### Documentation

Please note that we place high importance on documentation, which we host as [Teams SDK github pages](https://microsoft.github.io/teams-sdk/).

### Testing changes

Please use any of the agents in the `tests` directory of the repo you are writing in. These apps use the latest local changes and are intended to quickly set up and test feature work, bug fixes, etc.


================================================
FILE: LICENSE
================================================
Copyright (c) Microsoft Corporation.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
# Welcome to the Teams SDK ([Docs](https://microsoft.github.io/teams-sdk/))

Teams SDK represents a fundamental reimagining of how Teams apps and AI agents are built, while maintaining compatibility with existing botframework-based agents. This new version focuses on developer experience, simplified architecture, and enhanced AI capabilities.

For a detailed explanation of the motivations and architectural decisions behind v2, please see our [WHY.md](https://microsoft.github.io/teams-sdk/why) document.

## We have a new name!

We are very excited to announce that "Teams AI" is now officially "Teams SDK"! This change reflects our commitment to providing a comprehensive development framework for building all types of Teams applications, including AI-powered agents.

## Code repositories per SDK language

The SDK code for each language are in individual repos:

- [Typescript](https://github.com/microsoft/teams.ts)
- [C#](https://github.com/microsoft/teams.net)
- [Python](https://github.com/microsoft/teams.py)

For language-specific bugs or issues, please use the Issues tab in the respective language repository.

## Agent Accelerator Templates

You can find a set of open-source agent accelerator templates in the [Teams Agent Accelerators repository](https://github.com/microsoft/teams-agent-accelerator-templates). These templates provide a great starting point for building your own agents using the Teams SDK.

### Quick start

The Teams SDK CLI makes it easy to bootstrap your first agent. First, install the CLI via NPM:

```sh
npm install -g @microsoft/teams.cli
```

Next, use the CLI to create your agent:

```sh
npx @microsoft/teams.cli new <typescript | csharp | python> quote-agent --template echo
```

For more information, follow our quickstart guide: [C#](http://microsoft.github.io/teams-sdk/csharp/getting-started/quickstart), [Typescript](http://microsoft.github.io/teams-sdk/typescript/getting-started/quickstart), [Python](http://microsoft.github.io/teams-sdk/python/getting-started/quickstart)

### SDK

Microsoft Teams has a robust developer ecosystem with a broad suite of capabilities, now unified via Teams SDK. Whether you are building AI-powered agents ([TS](https://microsoft.github.io/teams-sdk/typescript/in-depth-guides/ai/), [C#](https://microsoft.github.io/teams-sdk/csharp/in-depth-guides/ai/), [Python](https://microsoft.github.io/teams-sdk/python/in-depth-guides/ai/)), Message Extensions ([TS](https://microsoft.github.io/teams-sdk/typescript/in-depth-guides/message-extensions/), [C#](https://microsoft.github.io/teams-sdk/csharp/in-depth-guides/message-extensions/), [Python](https://microsoft.github.io/teams-sdk/python/in-depth-guides/message-extensions/)), embedded web applications, or Graph, Teams SDK has you covered.

Here is a simple example, which responds to incoming messages with information retrieved from Graph.

```typescript
import { App } from '@microsoft/teams.apps';
import { DevtoolsPlugin } from '@microsoft/teams.dev';
import * as endpoints from '@microsoft/teams.graph-endpoints';

const app = new App({
  plugins: [new DevtoolsPlugin()],
});

// Listen for incoming messages
app.on('message', async ({ userGraph, isSignedIn, send, signin }) => {
  if (!isSignedIn) {
    await signin(); // initiates Entra login flow
    return;
  }
  const me = await userGraph.call(endpoints.me.get);
  await send(`Hello, ${me.displayName} from Earth!`);
});

// Start your application
(async () => {
  await app.start();
})();
```

For language-specific bugs or issues, please use the Issues tab in the respective language repository.

## Important: v1 to v2 Transition Notice

**This repository has transitioned from v1 to v2 as the main branch.**

- The `main` branch now contains v2 code, which was previously developed on the `v2-preview` branch.
- The previous `main` branch (v1) has been moved to the [`release/v1`](https://github.com/microsoft/teams-sdk/tree/release/v1) branch. We will continue to provide critical bug fixes and security patches for v1 on this branch.

## Documentation

For comprehensive documentation, API references, and examples, visit our [documentation site](https://microsoft.github.io/teams-sdk/).


================================================
FILE: SECURITY.md
================================================
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->


================================================
FILE: package.json
================================================
{
  "name": "teams-sdk",
  "private": true,
  "scripts": {
    "clean": "npx turbo clean",
    "build": "npx turbo build",
    "build:packages": "npx turbo build --filter=./packages/*",
    "dev": "npx turbo dev",
    "lint": "npx turbo lint",
    "lint:fix": "npx turbo lint:fix",
    "test": "npx turbo test --concurrency=100%",
    "fmt": "npx prettier --write \"**/*.{js,ts,tsx,md,json}\"",
    "docs:build": "npm -w teams-md run build",
    "docs:dev": "npm -w teams-md run start",
    "docs:serve": "npm -w teams-md run serve"
  },
  "devDependencies": {
    "prettier": "^3.5.3",
    "turbo": "^2.5.0",
    "typescript": "5.8.2"
  },
  "engines": {
    "node": ">=20"
  },
  "packageManager": "npm@10.9.2",
  "workspaces": [
    "packages/*",
    "teams.md"
  ],
  "tsconfig": {
    "exclude": [
      "node_modules"
    ]
  }
}


================================================
FILE: packages/README.md
================================================
# This is a blank file

This is a blank folder currently. We will add packages that are common to all submodules here.


================================================
FILE: prettier.config.js
================================================
// prettier.config.js, .prettierrc.js, prettier.config.cjs, or .prettierrc.cjs

/**
 * @see https://prettier.io/docs/en/configuration.html
 * @type {import("prettier").Config}
 */
const config = {
  trailingComma: 'es5',
  semi: true,
  singleQuote: true,
  printWidth: 100,
};

module.exports = config;


================================================
FILE: teams.md/.gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto


================================================
FILE: teams.md/.gitignore
================================================
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader
scripts/generated/

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

static/llms_docs/

================================================
FILE: teams.md/LANGUAGE-INCLUDE.md
================================================
# Language-Specific Documentation System

## Table of Contents

- [Quick Start](#quick-start)
- [Architecture](#architecture)
- [Core Concepts](#core-concepts)
  - [Templates](#templates-srcpagestemplatesmdx)
  - [Fragments](#fragments-srccomponentsincludelangincmd)
- [Commands](#commands)
- [Language Filtering](#language-filtering)
- [Page Types](#page-types)
- [Directory Structure](#directory-structure)
- [Workflow](#workflow)
- [Error Handling](#error-handling)
  - [Development Error Messages](#development-error-messages)
  - [Content Gaps Tracking](#content-gaps-tracking)
- [Summary](#summary)
- [Best Practices](#best-practices)
- [Migration Guide](#migration-guide)
- [Troubleshooting](#troubleshooting)

This documentation system maintains a single source of truth for content across multiple programming languages (TypeScript, C#, Python), with language-specific fragments embedded within shared templates.

## Quick Start

1. **Create template**: `src/pages/templates/my-guide.mdx` with `<LanguageInclude section="example" />` tags
2. **Create fragments**: `src/components/include/my-guide/{lang}.incl.md` with `<!-- example -->` sections
3. **Generate**: `npm run generate:docs` or `npm start`

## Architecture

```
src/pages/templates/    ← Templates with <LanguageInclude /> tags
     ↓ (generate-language-docs.ts)
src/components/include/ ← Language-specific fragments ({lang}.incl.md)
     ↓ (Build-time processing)
docs/main/{lang}/      ← Auto-generated files (fully resolved)
     ↓ (Docusaurus)
Final rendered page    ← Language-specific content only
```

## Core Concepts

[⭐ Skip to Best Practices section](#best-practices)

### Templates (`src/pages/templates/**/*.mdx`)

Your source of truth - write common content once with `<LanguageInclude />` placeholders:

```mdx
---
title: Getting Started
languages: ['typescript', 'python'] # Optional: restrict languages to render documentation for
---

# Getting Started

Shared content for all languages.

<LanguageInclude section="install" />  <!-- Block-level: full Markdown from include files -->

The package name is <LanguageInclude section="package-name" />. <!-- Inline: from include files -->

<!-- NEW: Inline content without separate include files -->
The context type is <LanguageInclude content={{"typescript": "`IContext`", "python": "`Context`"}} />.
```

### Fragments (`src/components/include/**/{lang}.incl.md`)

Language-specific content organized by HTML comment sections:

````markdown
<!-- install -->

```bash
npm install @microsoft/teams.ts
```

<!-- package-name -->

@microsoft/teams.ts

<!-- advanced -->

N/A
````

**Fragment Rules:**

- `<!-- sectionName -->` marks section start
- Content continues until next section or file end
- Use `N/A` to intentionally skip sections (e.g., when a section is necessary for one or two languages, but not all three)
- Full Markdown/MDX supported for block-level content

**Directory Mapping:**

- Category pages: `src/components/include/{category}/{lang}.incl.md`
- Regular pages: `src/components/include/{category}/{filename}/{lang}.incl.md`

### Inline Content

For simple, short language-specific text (like API names, method names, or simple phrases), you can use inline content directly in templates without creating separate include files:

```mdx
<LanguageInclude content={{"typescript": "`send`", "csharp": "`SendAsync`", "python": "`send`"}} />
```

**When to use inline content:**
- Short text snippets (API names, method names, parameter names)
- Simple differences between languages
- Content that's easier to read inline than in separate files

**When to use include files:**
- Code examples
- Complex or multi-line content
- Content that benefits from syntax highlighting
- Larger documentation sections

## Language Filtering

Control which languages generate pages using frontmatter:

```mdx
---
title: TypeScript-only Feature
languages: ['typescript'] # Restrict rendering to specific languages. If all languages are supported, omit this field.
suppressLanguageIncludeWarning: true # Suppress warnings for static content
---
```

**Important**: When a template file has `languages` frontmatter that restricts to specific languages, you should only create include files for those supported languages. For example, if a template is restricted to `['typescript', 'python']`, you should not create a `csharp.incl.md` file - only create `typescript.incl.md` and `python.incl.md`.

Useful for:

_- Language-specific features
_- Migration periods

- Framework-specific documentation

## Page Types

- **Category pages**: `README.mdx` → `index.mdx`
- **Regular pages**: `filename.mdx` → `filename.mdx`
- **Hidden pages**: `_filename.mdx` (accessible but hidden from sidebar)

## Directory Structure

```
src/pages/templates/
├── getting-started/
│   ├── README.mdx              # → index.mdx
│   ├── quickstart.mdx
│   └── _category_.json

src/components/include/
├── getting-started/            # For README.mdx
│   ├── typescript.incl.md
│   ├── csharp.incl.md
│   └── python.incl.md
└── getting-started/
    └── quickstart/             # For quickstart.mdx
        ├── typescript.incl.md
        ├── csharp.incl.md
        └── python.incl.md

docs/main/{lang}/               # Auto-generated (DO NOT EDIT)
├── getting-started/
│   ├── index.mdx
│   └── quickstart.mdx
```

## Workflow

1. **Create template**: `src/pages/templates/my-guide.mdx`
2. **Create fragments**: `src/components/include/my-guide/{lang}.incl.md`
3. **Generate**: `npm run generate:docs` and `npm start`

## Error Handling

- **Missing files/sections**: Console warnings (unless language-restricted)
- **Empty sections**: Show development error messages
- **N/A sections**: Use `N/A` or `not applicable` to intentionally skip sections
- **Development mode**: Error messages rendered in browser with markdown formatting
- **Production mode**: Clean files without error content
- **Page availability**: Tracked in `static/missing-pages.json`
- **Content gaps**: Tracked in `scripts/generated/content-gaps.json` and `content-gaps.md`

### Development Error Messages

When sections are missing or empty, you'll see helpful error messages:

```markdown
**[Dev] Section "install" not found in TypeScript documentation.**
Either mark the section explicitly as N/A for intentionally ignored, or fill in documentation.
```

### Content Gaps Tracking

The system now generates development reports to help track missing documentation:

- **JSON manifest**: `scripts/generated/content-gaps.json` - Machine-readable data
- **Markdown report**: `scripts/generated/content-gaps.md` - Human-readable summary
- **Automatic generation**: Created every time docs are generated
- **Git ignored**: Reports are not committed to the repository

Example content gaps report:

```markdown
# Content Gaps Report

**8 template(s) have missing sections**

## `in-depth-guides/ai/function-calling.mdx`

- **`advanced-features`**: Missing in C#, Python

## Summary

- **8** templates with gaps
- **27** total missing sections
```

## Best Practices

1. **Never edit `docs/main/{lang}/` files** - they're auto-generated
2. **Use `languages: ['lang1', 'lang2']` frontmatter** for language-specific pages
3. **Add `suppressLanguageIncludeWarning: true`** for static content pages
4. **Keep section names consistent** across all fragment files
5. **Use `N/A` or `not applicable` explicitly** when a section doesn't apply to a language
6. **Distinguish between missing and intentional**: Empty sections show errors, `N/A` sections are silently skipped
7. **Test all supported languages** before committing
8. **Use block-level tags for rich content**, inline tags for simple text
9. **Add `title`** to frontmatter for proper capitalization and navigation rendering
   - Use `sidebar_label` to customize sidebar text if needed
10. **Prefix utility pages with underscore** to hide from sidebar
11. **Use correct relative URLs** (no extensions, relative to generated location)
12. **Remove file suffixes from markdown links** - use `[link](../page)` not `[link](../page.md)` or `[link](../README.md)`
13. **Check `missing-pages.json`** after generation to verify restrictions
14. **Review content gaps report** at `scripts/generated/content-gaps.md` to track missing documentation

## Migration Guide

1. **Analyze differences** between existing language versions
2. **Extract common content** → template file
3. **Extract language-specific content** → include files
4. **Create template and includes** following directory structure
5. **Generate and test** all languages
6. **Remove old files** from `docs/{lang}/`

## Troubleshooting

- **Translation conflicts**: Regenerate with `npm run generate:docs`
- **Missing sidebar labels**: Add `sidebar_label: "Name"` to frontmatter
- **Language dropdown issues**: Ensure `missing-pages.json` exists
- **Banner not dismissing**: Check browser console for errors
- **Unexpected warnings**: Add `suppressLanguageIncludeWarning: true`
- **Empty vs N/A sections**: Use `N/A` to intentionally skip; empty sections will show dev errors
- **Content gaps tracking**: Check `scripts/generated/content-gaps.md` for missing documentation overview


================================================
FILE: teams.md/README.md
================================================
# Website

This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.

### Installation

```
$ npm install
```

### Local Development

```
$ npm run start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

### Build

```
$ npm run build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

### Generate LLM.txt files

```
$ npm run generate:llms
```

This command generates `LLM.txt` files used for SEO purposes.

### Generate docs

```
$ npm run generate:docs
```

This command generates documentation files for the website using the custom LanguageInclude system. To see how to use LanguageInclude, check out the [Language Include documentation](./LANGUAGE-INCLUDE.md).

### Watch docs generation

```
$ npm run generate:docs:watch
```

Watches for changes and regenerates documentation files automatically.

### TypeScript type checking

```
$ npm run typecheck
```

Runs TypeScript type checking on the codebase.

### Prebuild

```
$ npm run prebuild
```

Runs docs generation before building the site.

### Scaffold folders/files

```
$ npm run scaffold -- <path>
```

Scaffolds template/include folders and files. See `src/scripts/scaffold.js` for details.


================================================
FILE: teams.md/docs/main/developer-tools/README.md
================================================
---
sidebar_position: 4
summary: Overview of developer tools in Teams SDK including the CLI for project management and DevTools for testing and debugging agents.
---

# Developer Tools

One of the main motivations for Teams SDK is to provide excellent tools that simplify and speed up building and testing agents. Because of this, we created the CLI for speedy agent initiation and project management, and DevTools as an accessible way to test your agent's behavior without jumping through deployment hoops. DevTools also provides crucial insight on activity payloads on the Activities page.

Learn more about the developer tools that come with Teams SDK.

1. [Teams CLI](./cli)
2. [DevTools](./devtools)


================================================
FILE: teams.md/docs/main/developer-tools/_category_.json
================================================
{
  "position": 5,
  "label": "Developer Tools",
  "collapsed": true
}


================================================
FILE: teams.md/docs/main/developer-tools/cli.md
================================================
---
sidebar_position: 1
summary: Comprehensive guide to the Teams CLI tool for creating, managing, and deploying Teams SDK applications with simple command-line operations. Use this when you need to set up a new Teams SDK agent or manage existing ones.
---

# Teams CLI

The Teams CLI was created with the intent of supporting developers by making common actions simple to implement with just a command line. The CLI overarching features are:

| Feature       | Description                                                                                          |
| ------------- | ---------------------------------------------------------------------------------------------------- |
| `new`         | Create a new Teams SDK agent by choosing a template that will be ready to run with one command line. |
| `config`      | Add Microsoft 365 Agents Toolkit configuration files to your existing Teams SDK agent project.       |
| `environment` | Manage multiple environments (e.g. dev, prod) and their keys for your agent.                         |

:::tip
With the CLI, you can enter `npx @microsoft/teams.cli <token-arguments> --help` at any command level to access information about the command, tokens, or required arguments.
:::

## Create an agent with one command line

```sh
npx @microsoft/teams.cli@latest new <typscript | csharp | python> <app-name> <optional>
```

The `new` token will create a brand new agent with `app-name` applied as the directory name and project name.

:::note
The name you choose may have case changes when applied; for example, "My App" would become "my-app' due to the requirements for `package.json` files.
:::

:::warning
Our Python SDK is currently in Public Preview. As a result, we have the CLI under a feature flag.
Please run the below command to enable this language.
:::

```sh
$env:ENABLE_EXPERIMENTAL_PYTHON_OPTIONS = 1
```

### Optional parameters

:::tip
Use command line `npx @microsoft/teams.cli --help` to see the latest options for all optional params.
:::

| Parameter              | Description                                                                                                                                                                                                                                                 |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--template`           | Ready-to-run templates that serve as a starting point depending on your scenario. Template examples include `ai`, `echo`, `graph`, and more.                                                                                                                |
| `--start`              | Run the agent immediately upon finishing the creation of the project.                                                                                                                                                                                       |
| `--toolkit` or `--atk` | Include the configuration files required to run the agent in the debugger via the [Microsoft 365 Agents Toolkit](https://github.com/OfficeDev/teams-toolkit) extension. Options include `basic`, `embed`, and `oauth`, and more may be added in the future. |
| `--client-id`          | The app client id, if you already have deployed a resource. This will be added to the root `.env` file of the project.                                                                                                                                      |
| `--client-secret`      | The app client secret, if you already have deployed a resource. This will be added to the root `.env` file of the project.                                                                                                                                  |

## Add Microsoft 365 Agents Toolkit configuration to existing agent

An existing project may also have the appropriate Microsoft 365 Agents Toolkit configuration files added by configuration name.

```bash
npx @microsoft/teams.cli config add <config-name>
```

| Configuration | Description                                      |
| ------------- | ------------------------------------------------ |
| `atk.basic`   | Basic Microsoft 365 Agents Toolkit configuration |
| `atk.embed`   | Configuration for embedded Teams applications    |
| `atk.oauth`   | Configuration for OAuth-enabled applications     |

Using this command will include

- `env`: folders for managing multiple environments
- `infra`: files for deployment and provisioning
- `.yml` files for tasks, launch, deployment, etc.

## Remove Agents Toolkit configuration files

```bash
npx @microsoft/teams.cli config remove <config-name>
```


================================================
FILE: teams.md/docs/main/developer-tools/devtools/README.md
================================================
---
sidebar_position: 2
summary: Use DevTools to locally test Teams apps with chat, activity inspection, and card design features.
llms: ignore
---

# 🛠️ DevTools

The developer tools can be used to locally interact with an app to streamline the testing/development process,
preventing you from needing to deploy/register the app or expose a public endpoint.

![Screenshot of DevTools showing user prompt 'hello!' and agent response 'you said hello!'.](/screenshots/devtools-echo-chat.png)

## Basic features

- **Chat**: Chat with your app the same way you would in Teams without the need for an app id or authentication. This is useful for testing and debugging your app.
- **Inspect**: Inspect incoming and outgoing activities on DevTools' Activity page. All activity on your agent logged here, including messages, reactions, and more.
- **Cards**: Use the Cards page to visually design and test your cards.

Continue on to the next pages to learn more about the features available in DevTools.


================================================
FILE: teams.md/docs/main/developer-tools/devtools/cards.md
================================================
---
sidebar_position: 3
summary: Design and test Adaptive Cards using the DevTools card designer with live preview and JSON editing.
llms: ignore
---

# 🪪 Cards

Use the Cards page to design and test your cards. Then, use the "Attach card" button to add that card as an attachment to your message. By default, the card will be attached in the new message compose box, but you can also attach a card when editing an existing message.

![Card Designer Typescript](https://github.com/microsoft/teams.ts/blob/main/assets/screenshots/adaptive-cards-designer.png?raw=true)

## Using the card designer from Chat

Add an attachment to your message by clicking the attachment (paperclip) icon in the compose box. Select "Open card designer" from the dropdown menu, and your card will be added as an attachment to the same message you are composing or editing after you click "Attach card".

:::tip
DevTools stores your card attachment so you can use it between page navigation (Chat to Cards and back). Only the last card you designed will be stored, and only temporarily, so if you want to save a card, make sure to save the payload to a file or copy it to your clipboard.
Also check out the **[Adaptive Cards Designer](https://adaptivecards.microsoft.com/designer)** and [documentation](https://adaptivecards.microsoft.com/designer).
:::

## Pasting Adaptive Card JSON

You can also use the "Paste custom JSON" menu option to paste an Adaptive Card JSON payload into the dialog that will renders. This adds the attachment to the message you are composing or editing.

Please keep an eye out for a big update coming soon!


================================================
FILE: teams.md/docs/main/developer-tools/devtools/chat.md
================================================
---
sidebar_position: 1
summary: Test chat functionality with your Teams agent using the lightweight DevTools without sideloading into Teams.
llms: ignore
---

# 💬 Devtools chat

Use the lightweight DevTools app that allows you to test chat functionality with your agent without the need to sideload into Teams. This is useful for testing and debugging.

![Empty DevTools chat](https://github.com/microsoft/teams.ts/blob/main/assets/screenshots/devtools_blank_chat.png?raw=true)

:::note
We plan to add more features to DevTools for a wider variety of testing. Stay tuned!
:::

## Using DevTools

Use the Teams SDK dev package as a plugin.

### Installation

Add the dev package to your Teams app.

```bash
$: npm install @microsoft/teams.dev
```

### Usage

In your app's main file, ensure DevTools plugin is added to the app.

:::warning
DevTools is not secure and should not be used in production environments. Remove the plugin before deploying your app to production.
:::

```typescript
import { App } from '@microsoft/teams.apps';
import { ConsoleLogger } from '@microsoft/teams.common/logging';
import { DevtoolsPlugin } from '@microsoft/teams.dev';
//... Other imports here
const app = new App({
  logger: new ConsoleLogger('@samples/echo', { level: 'debug' }),
  plugins: [new DevtoolsPlugin()],
});
```

When you run your app, for example `npm run dev`, devtools will be running on port 3979

```bash
[nodemon] watching extensions: ts
[nodemon] starting `node -r ts-node/register -r dotenv/config ./src/index.ts`
[INFO] @samples/echo/http listening on port 3978 🚀
[INFO] @samples/echo/devtools available at http://localhost:3979/devtools
```

:::info
If you used the [CLI](../cli) to create an `atk` configuration for your app, DevTools will run on port 3979 when you launch the debugger.
:::

When you open the page, you will see a Teams-like chat window and you can immediately interact with your agent.

![Screenshot of DevTools showing user prompt 'hello!' and agent response 'you said hello!'.](/screenshots/devtools-echo-chat.png)

## Teams chat terminology

Below is a brief list of the terminology used in the chat window and in Teams:

1. **Compose box**: The area where you type your message and attach files. A newly rendered Chat page will automatically focus on the compose box.
2. **Message actions menu**: The menu that appears when you hover over or focus on a message, offering different actions depending on whether you sent or received the message.

## Chat capabilities

The chat window emulates Teams features as closely as possible. Not all Teams features are available in DevTools, but we are working to add more features over time. The following capabilities are available:

:::info
Accessibility and keyboard navigation is not fully supported in DevTools. Full support for all users is important to us, and we will prioritize acessibility in future preview releases.
:::

### Send messages

You can send messages to your agent just like in Teams. In the compose box, type your message and press <kbd>Enter</kbd> to send it.

### Attachments

Attach up to 10 files to your message using the Attach (paperclip) button. DevTools supports pasting an Adaptive Card JSON or attaching a card from the card designer. See the [Cards page](./cards) for more.

:::note
Further support for attachments is coming soon!
:::

### Connectivity

Check your app's connectivity in three ways:

1. The DevTools banner shows a green badge or 'Connected' text when connected, and red or 'Disconnected' when not.
2. Similarly, the agent's avatar shows a 'Connected' or 'Disconnected' badge.
3. DevTools uses the `ConsoleLogger` that logs connectivity events to the console. Use the browser's console tool to see the logs.

### Message reactions

You can react to messages by selecting an emoji in the message actions menu.

![Devtools react to a message](https://github.com/microsoft/teams.ts/blob/main/assets/screenshots/devtools_message_reaction.gif?raw=true)

### Edit your message

Edit messages by selecting the Edit (pencil) icon from the message actions menu. Press Enter or the checkmark button to send the edited message, or the Dismiss (X) button to cancel.

### Delete your message

Soft delete messages by hovering over your message, pressing the More (ellipsis) button, then the Delete (trash) button. Click "Undo" to restore the message.

### Streaming

If your agent is using streaming, DevTools will render messages as a stream with a rainbow border until the stream ends. See the full stream on the [Activities](inspect) page by clicking the Inspect (magnifying glass) button in the message actions menu of the message.

### Feedback

Send feedback to your app by clicking the Feedback (thumbs up/down) buttons in the message actions menu and completing the dialog form.

:::info
The capabilities above will also populate activities to the Activities page, where you can inspect activity payloads and see the full activity history.
:::

### Developer message shortcut

For easier debugging, the compose box stores the last five messages sent to the app. Press the Up <kbd>↑</kbd> arrow key to cycle through your message history and resend messages.

![Devtools Up Arrow Feature](https://github.com/microsoft/teams.ts/blob/main/assets/screenshots/devtools_uparrow_feature.gif?raw=true)


================================================
FILE: teams.md/docs/main/developer-tools/devtools/inspect.md
================================================
---
sidebar_position: 2
summary: Inspect all incoming and outgoing activities with your agent using DevTools Activities page for debugging.
llms: ignore
---

# 🔍 Inspect activities

Inspect incoming and outgoing activities on DevTools' Activities page. All interactions with your agent are logged here, including messages, reactions, and more.
![Inspect Activities view](https://github.com/microsoft/teams.ts/blob/main/assets/screenshots/inspect_activity.png?raw=true)

## View all activity

The Activities page displays all activities sent to and from your agent in a grid, showing:

1. Activity type (message, reaction, etc.)
2. Direction via down arrow (incoming) or up arrow (outgoing)
3. Conversation type (for now, only personal chat is supported)
4. Sender
5. Timestamp.

### Monitor activity while testing Teams in browser

When testing your sideloaded app in the Teams web client, you can monitor activities in DevTools. Once your agent has launched, the agent server will indicate what port DevTools is running on). Open another browser tab and navigate to the DevTools Activities URL. Interact with your agent in the Teams web client and see the activities in DevTools. To learn more, review the [Agents Toolkit](../../teams/configuration/agents-toolkit) page.

You can filter activities by type using the filter icon in the Type column header.

### View activity details

Selecting an activity in the grid opens a detailed view in Preview mode, showing the full payload as a tree with expandable and collapsible sections.

### View activity JSON

Toggle from "Preview" to "JSON" under the "Activity details" header to see the raw JSON payload.

### Copy activity payload

Press the Copy button in the top right corner of the Activity details view to copy the payload to your clipboard.

### Inspect activities by ID

When in [Chat](chat), you can inspect activities by ID by clicking the magnifying glass icon in the message actions menu. This opens the Activities page with the activity ID filtered in the list, which is useful for inspecting streamed messages, which have multiple activities.

To reset the filter, use the filter button in the Type column header and de-select the activity ID to show all activities again.


================================================
FILE: teams.md/docs/main/privacy.md
================================================
---
sidebar_position: 5
summary: Privacy policy detailing data collection practices using Microsoft Clarity for website analytics and user behavior tracking.
llms: ignore
---

# Privacy Policy

We partner with Microsoft Clarity to capture how you use and interact with our website through behavioral metrics, heatmaps, and session replay to improve and market our products/services. Website usage data is captured using first and third-party cookies and other tracking technologies to determine the popularity of products/services and online activity. Additionally, we use this information for site optimization and fraud/security purposes. For more information about how Microsoft collects and uses your data, visit the [Microsoft Privacy Statement](https://www.microsoft.com/en-us/privacy/privacystatement).

================================================
FILE: teams.md/docs/main/teams/README.md
================================================
---
sidebar_position: 3
summary: Overview of Teams-specific features and SDK components that enable agent integration with the Microsoft Teams platform.
---

# Teams Integration

This section describes Teams-specific features and components of the SDK, helping you understand how your agent integrates with the Microsoft Teams platform.

## Core Concepts

When working with Teams, several key components come into play:

- **DevTunnel**: Enables local development by creating secure public endpoints
- **App Provisioning**: Handles registration and configuration in Teams
- **Environment Setup**: Manages Teams-specific configuration files
- **App Packaging**: Bundles your agent for Teams deployment

## In This Section

1. [Core Concepts](core-concepts) - Understanding the Teams deployment process and architecture
2. [Teams Manifest](manifest) - Configuring your agent's Teams presence
3. [Microsoft 365 Agents Toolkit](configuration/agents-toolkit) - Using the Agents Toolkit extension for sideloading, deployment, and provisioning
4. [Enabling in M365 Copilot](enabling-in-copilot) - Make your Teams app available in M365 Copilot

Each guide provides detailed information about specific aspects of Teams integration, from local development to production deployment.


================================================
FILE: teams.md/docs/main/teams/_category_.json
================================================
{
  "position": 2,
  "label": "Teams Integration",
  "collapsed": false
}


================================================
FILE: teams.md/docs/main/teams/app-authentication/README.mdx
================================================
---
sidebar_position: 4
summary: Set up authentication for your Teams bot using client secrets, user managed identities, or federated identity credentials
---

import LangLink from '@site/src/components/LangLink';

# App Authentication Setup

Your Teams bot needs to authenticate with Azure to send messages. This involves configuring your Azure Bot Service and App Registration correctly.

## Authentication Methods

Choose one of the following authentication methods based on your security requirements:

1. **[Client Secret](client-secret)** - Simple password-based authentication using a client secret
2. **[User Managed Identity](user-managed-identity)** - Passwordless authentication using Azure managed identities
3. **[Federated Identity Credentials](federated-identity-credentials)** - Advanced identity federation using managed identities assigned to App Registration

Each method has different setup requirements in Azure Portal or Azure CLI.

## After Setup

Once you've completed the Azure setup for your chosen authentication method, you'll need to configure your application code. See the <LangLink to="essentials/app-authentication">App Authentication configuration guide</LangLink> for details on environment variables and code configuration.

## Troubleshooting

If you encounter authentication errors, see the [Troubleshooting](troubleshooting) guide for common issues and solutions.


================================================
FILE: teams.md/docs/main/teams/app-authentication/_category_.json
================================================
{
  "label": "App Authentication Configuration",
  "position": 3,
  "collapsed": true
}


================================================
FILE: teams.md/docs/main/teams/app-authentication/client-secret.md
================================================
---
sidebar_position: 1
title: Client Secret Setup
summary: Set up client secret authentication for your Teams bot in Azure Portal or Azure CLI
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Client Secret Authentication Setup

Client Secret authentication is the simplest method, using a password-like secret to authenticate your bot. While easy to set up, secrets need to be rotated periodically and kept secure.

## Prerequisites

Before you begin, ensure you have:
- An Azure subscription
- Permissions to create App Registrations and Azure Bot Services

## Setup Steps

### Step 1: Create Azure Bot with Single Tenant

When creating your Azure Bot Service, you must select `Single Tenant` for the `Type of App`.

![Single Tenant Bot Creation](/screenshots/single-tenant-bot.png)

### Step 2: Create Client Secret

<Tabs>
<TabItem value="portal" label="Azure Portal">

1. Navigate to your **App Registration** in the Azure Portal
2. Go to **Certificates and Secrets**
3. Click **New client secret**
4. Add a description and select an expiration period
5. Click **Add**
6. **Important**: Copy the secret value immediately - it won't be shown again

![Secret in Certificates and Secrets](/screenshots/client-secret.png)

</TabItem>
<TabItem value="cli" label="Azure CLI">

```bash
# Create a new client secret
az ad app credential reset --id $APP_ID --append
```

The command will output the secret value. Save it securely.

</TabItem>
</Tabs>

## Next Steps

After completing the Azure setup, configure your application code with the appropriate environment variables. See the App Authentication Essentials Guide for details.


================================================
FILE: teams.md/docs/main/teams/app-authentication/federated-identity-credentials.md
================================================
---
sidebar_position: 3
title: Federated Identity Credentials Setup
summary: Set up Federated Identity Credentials authentication for your Teams bot in Azure Portal or Azure CLI
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Federated Identity Credentials Setup

Federated Identity Credentials (FIC) allows you to assign managed identities directly to your App Registration instead of creating a separate User Managed Identity resource.

## Prerequisites

Before you begin, ensure you have:
- An Azure subscription
- Permissions to create App Registrations, Azure Bot Services, and manage identities
- A compute resource where your bot will be hosted (App Service, Container App, VM, etc.)
- Either a User Managed Identity or the ability to use System Assigned Identity

## Setup Steps

### Step 1: Create Azure Bot with Single Tenant

When creating your Azure Bot Service, select `Single Tenant` for the `Type of App`.

![Single Tenant Bot Creation](/screenshots/single-tenant-bot.png)

### Step 2: Configure Federated Credentials

Assign managed identities to your App Registration using Federated Credentials.

<Tabs>
<TabItem value="portal" label="Azure Portal">

1. Navigate to your **App Registration** in the Azure Portal
2. Go to **Certificates and Secrets**
3. Select the **Federated Credentials** tab
4. Click **Add credential**
5. Select the federated credential scenario (e.g., "Customer managed keys")
6. Choose the User Managed Identity or configure for System Assigned Identity
7. Complete the required fields and click **Add**

![Federated Identity Creds](/screenshots/fic.png)

The identity you select here must also be assigned to the compute resource where your application is hosted.

</TabItem>
<TabItem value="cli" label="Azure CLI">

```bash
# Add a federated credential for a user managed identity
az ad app federated-credential create \
  --id $APP_ID \
  --parameters '{
    "name": "MyFederatedCredential",
    "issuer": "https://login.microsoftonline.com/'$TENANT_ID'/v2.0",
    "subject": "'$MANAGED_IDENTITY_CLIENT_ID'",
    "audiences": ["api://AzureADTokenExchange"]
  }'
```

</TabItem>
</Tabs>

### Step 3: Assign the Managed Identity to Your Compute Resource

The managed identity configured in the federated credential must be assigned to your compute resource.

<Tabs>
<TabItem value="portal" label="Azure Portal">

**For User Managed Identity:**

1. Navigate to your compute resource in the Azure Portal
2. Go to **Identity** section in the left menu
3. Select the **User assigned** tab
4. Click **Add**
5. Select the User Managed Identity you configured in the federated credential
6. Click **Add** to confirm

**For System Assigned Identity:**

1. Navigate to your compute resource in the Azure Portal
2. Go to **Identity** section in the left menu
3. Select the **System assigned** tab
4. Set **Status** to **On**
5. Click **Save**

</TabItem>
<TabItem value="cli" label="Azure CLI">

```bash
# For user managed identity:
az webapp identity assign \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --identities $MANAGED_IDENTITY_RESOURCE_ID

# For system assigned identity:
az webapp identity assign \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP
```

</TabItem>
</Tabs>

## Next Steps

After completing the Azure setup, configure your application code with the appropriate environment variables. See the App Authentication Essentials Guide for details.


================================================
FILE: teams.md/docs/main/teams/app-authentication/troubleshooting.md
================================================
---
sidebar_position: 4
title: Troubleshooting
summary: Common authentication errors and how to resolve them
llms: ignore
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Authentication Troubleshooting

This guide covers common authentication errors and their solutions.

## Missing Service Principal in the Tenant

This error occurs when the application has a single-tenant Azure Bot Service (`msaAppType: 'SingleTenant'`) instance, but your app registration has not yet been linked to a Service Principal in the tenant.

### Error Examples

<Tabs>
<TabItem value="typescript" label="TypeScript">

```sh
[ERROR] @teams/app Request failed with status code 401
[ERROR] @teams/app /aaaabbbb-0000-cccc-1111-dddd2222eeee/oauth2/v2.0/token
[ERROR] @teams/app {
[ERROR] @teams/app   "error": "invalid_client",
[ERROR] @teams/app   "error_description": "AADSTS7000229: The client application 00001111-aaaa-2222-bbbb-3333cccc4444 is missing service principal in the tenant aaaabbbb-0000-cccc-1111-dddd2222eeee. See instructions here: https://go.microsoft.com/fwlink/?linkid=2225119 Trace ID: 0000aaaa-11bb-cccc-dd22-eeeeee333333 Correlation ID: aaaa0000-bb11-2222-33cc-444444dddddd Timestamp: 2025-09-18 01:17:37Z",
[ERROR] @teams/app   "error_codes": [
[ERROR] @teams/app     7000229
[ERROR] @teams/app   ],
[ERROR] @teams/app   "timestamp": "2025-09-18 01:17:37Z",
[ERROR] @teams/app   "trace_id": "0000aaaa-11bb-cccc-dd22-eeeeee333333",
[ERROR] @teams/app   "correlation_id": "aaaa0000-bb11-2222-33cc-444444dddddd",
[ERROR] @teams/app   "error_uri": "https://login.microsoftonline.com/error?code=7000229"
[ERROR] @teams/app }
```

</TabItem>
<TabItem value="python" label="Python">

```sh
[ERROR] @teams/app Failed to refresh bot token: Client error '401 Unauthorized' for url 'https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/oauth2/v2.0/token'
[ERROR] @teams/app For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401
```

</TabItem>
<TabItem value="csharp" label="C#">

```sh
[ERROR] Echobot Failed to get bot token on app startup.
[ERROR] Echobot {
[ERROR] Echobot   "error": "invalid_client",
[ERROR] Echobot   "error_description": "AADSTS7000229: The client application 00001111-aaaa-2222-bbbb-3333cccc4444 is missing service principal in the tenant aaaabbbb-0000-cccc-1111-dddd2222eeee. See instructions here: https://go.microsoft.com/fwlink/?linkid=2225119 Trace ID: 0000aaaa-11bb-cccc-dd22-eeeeee333333 Correlation ID: aaaa0000-bb11-2222-33cc-444444dddddd Timestamp: 2025-09-18 02:26:20Z",
[ERROR] Echobot   "error_codes": [
[ERROR] Echobot     7000229
[ERROR] Echobot   ],
[ERROR] Echobot   "timestamp": "2025-09-18 02:26:20Z",
[ERROR] Echobot   "trace_id": "0000aaaa-11bb-cccc-dd22-eeeeee333333",
[ERROR] Echobot   "correlation_id": "aaaa0000-bb11-2222-33cc-444444dddddd",
[ERROR] Echobot   "error_uri": "https://login.microsoftonline.com/error?code=7000229"
[ERROR] Echobot }
```

</TabItem>
</Tabs>

### Solution

1. **Sign in to Azure Portal**
   Go to [https://portal.azure.com](https://portal.azure.com) and log in with your Azure account.

2. **Navigate to App Registrations**
   In the top search bar, search for **App registrations** and select it.

3. **Search for your application**
   Use the **BOT_ID** from your environment file:
   - Local development → `env/.env.local`
   - Azure deployment → `env/.env.dev`

4. **Check if a Service Principal exists**
   Open the app registration and verify if a Service Principal is created. If it exists already, you should see an entry for a **Managed Application in your local directory**.

   ![Screenshot of App Registrations pane in Azure Portal showing value of 'Graphlocal' under the 'Managed application in local directory' field.](/screenshots/existing-service-principal.png)

5. **Create a Service Principal if missing**
   If it doesn't exist, click **Create Service Principal**. Wait for the page to finish loading.

   ![Screenshot of App Registrations pane in Azure Portal showing value of 'Create Service Principal' under the 'Managed application in local directory' field.](/screenshots/create-service-principal.png)

6. **Restart your app**
   Once the Service Principal is created, restart your application.


================================================
FILE: teams.md/docs/main/teams/app-authentication/user-managed-identity.md
================================================
---
sidebar_position: 2
title: User Managed Identity Setup
summary: Set up User Managed Identity authentication for your Teams bot in Azure Portal or Azure CLI
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# User Managed Identity Authentication Setup

User Managed Identity authentication eliminates the need for secrets or passwords. A managed identity is created alongside your bot and assigned to your compute resource (App Service, Container App, VM, etc.).

## Prerequisites

Before you begin, ensure you have:
- An Azure subscription
- Permissions to create App Registrations, Azure Bot Services, and manage identities
- A compute resource where your bot will be hosted (App Service, Container App, VM, etc.)

## Setup Steps

### Step 1: Create Azure Bot with User Managed Identity

When creating your Azure Bot Service, select `User Managed Identity` for the `Type of App`.

![User Managed Identity](/screenshots/umi-auth.png)

This will automatically create a User Managed Identity resource alongside your bot.

### Step 2: Assign the Managed Identity to Your Compute Resource

The User Managed Identity created with your bot must be assigned to the service running your application.

<Tabs>
<TabItem value="portal" label="Azure Portal">

1. Navigate to your compute resource (App Service, Container App, VM, etc.) in the Azure Portal
2. Go to **Identity** section in the left menu
3. Select the **User assigned** tab
4. Click **Add**
5. Select the User Managed Identity that was created with your Azure Bot
6. Click **Add** to confirm

</TabItem>
<TabItem value="cli" label="Azure CLI">

```bash
# Assign user managed identity to your compute resource
# Example for App Service:
az webapp identity assign \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --identities $MANAGED_IDENTITY_RESOURCE_ID

# Example for Container App:
az containerapp identity assign \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --user-assigned $MANAGED_IDENTITY_RESOURCE_ID
```

</TabItem>
</Tabs>

## Next Steps

After completing the Azure setup, configure your application code with the appropriate environment variables. See the App Authentication Essentials Guide for details.


================================================
FILE: teams.md/docs/main/teams/configuration/README.md
================================================
# Basic Configuration

After learning about the [core concepts](./../core-concepts) on how to enable an application in Teams, this guide will help you configure the underlying resources correctly in Azure. There are two main ways of doing this integration.

1. Using [M365 Agents Toolkit](./agents-toolkit.md) which uses a CLI/VSCode extension to help automate that work for you.
2. [Manually Configuration](./manual-configuration.mdx) if you have a setup that deviates from something simple


================================================
FILE: teams.md/docs/main/teams/configuration/_category_.json
================================================
{
  "position": 2,
  "label": "Basic Configuration",
  "collapsed": true
}


================================================
FILE: teams.md/docs/main/teams/configuration/agents-toolkit.md
================================================
---
sidebar_position: 1
summary: Automate Teams app development with Microsoft 365 Agents Toolkit for manifest management, sideloading, and deployment.
---

# Microsoft 365 Agents Toolkit

Microsoft 365 Agents Toolkit provides a powerful VS Code extension and CLI tool that helps automate important tasks like provisioning and deployment. The project is maintained separately in this repository - [Agents Toolkit GitHub repository](https://github.com/OfficeDev/microsoft-365-agents-toolkit).

## Installing Agents Toolkit

Agents Toolkit can be installed as an extension and CLI. Please see the documentation linked below.

- [Installing Agents Toolkit extension](https://learn.microsoft.com/microsoftteams/platform/toolkit/install-teams-toolkit)
- [Installing Agents Toolkit CLI](https://learn.microsoft.com/microsoftteams/platform/toolkit/microsoft-365-agents-toolkit-cli)

:::note

- [Teams SDK CLI](../../developer-tools/cli) - helper for Teams SDK. It scaffolds agents, wires in deep Teams features (Adaptive Cards, Conversation History, Memory...etc), and adds all the config files you need while you're coding.
- Agents Toolkit CLI - app deployment helper. It sideloads, provisions Azure resources, handles manfiest/tenant plumbing, and keeps your dev, test, and prod environments in sync.
  :::

## Official documentation

Refer to the official [Microsoft 365 Agents Toolkit documentation](https://learn.microsoft.com/microsoft-365/developer/overview-m365-agents-toolkit?toc=%2Fmicrosoftteams%2Fplatform%2Ftoc.json&bc=%2Fmicrosoftteams%2Fplatform%2Fbreadcrumb%2Ftoc.json) on Microsoft Learn.

## Deployment and provisioning

Generally, you can use the toolkit to add required resources to Azure based on your app manifest setup. For more, see [Add cloud resources and API connection](https://learn.microsoft.com/microsoftteams/platform/toolkit/add-resource).

## Resources

- [Microsoft 365 Agents Toolkit](https://learn.microsoft.com/microsoftteams/platform/toolkit/teams-toolkit-fundamentals): Extensive documentation covering usage and supported scenarios of Agents Toolkit.
- [Teams SDK CLI documentation](../../developer-tools/cli): Instructions on adding Agents Toolkit configurations to your Teams SDK agent.


================================================
FILE: teams.md/docs/main/teams/configuration/manual-configuration.mdx
================================================
---
sidebar_position: 2
summary: Describe how to deploy the Azure Bot Service resource required for Teams bot apps
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Manual Configuration

If you prefer manually configuring the resources on Azure, and do not want to follow the automated process, you can follow the following guide.
As described in the [Core Concepts](../core-concepts) article, the main things required are an App Registration and an Azure Bot.

## Requirements

1. An Azure subscription
2. Permissions to create Entra ID App registrations. (If you don't have permissions in your tenant, ask your admin to create the App Registration and share the `Application Id`)
3. Permissions to create Azure Bot Service resources
4. (Optional) The [Azure CLI](https://aka.ms/azcli) installed and authenticated to your Azure subscription

### Create the Entra App Registration

After a successful App Registration you should have the `TenantId`, `ClientId` and `ClientSecret` values, that you will need later.

:::tip
We are using Client Secrets authentication here, but it is possible to use other types of authentication. See the [App Authentication](../app-authentication) setup guide for other methods.
:::

<Tabs>
<TabItem value="portal" label="Azure Portal">

1. Navigate to the [Entra Id App Registrations](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps)
2. Select `New App Registration` and provide a name. Take note of the assigned `Application Id` (also known as `ClientId`) and `TenantId`
3. Navigate to `Certificates & secrets` and create `New client secret`

</TabItem>
<TabItem value="cli" label="Azure CLI">

```bash
botName="My App"
appId=$(az ad app create --display-name $botName --sign-in-audience "AzureADMyOrg" --query appId -o tsv)
az ad sp create --id $appId
appCred=$(az ad app credential reset --id $appId)
tenantId=$(echo $appCred | jq -r '.tenant')
clientSecret=$(echo $appCred | jq -r '.password')
```

</TabItem>
</Tabs>

### Create the Azure Bot Service resource

:::tip
You can create the Azure Bot Service resource and the Entra App Registration from this screen, and then you will have to create a new client secret.
:::

<Tabs>
<TabItem value="portal" label="Azure Portal">

1. Create or select the resource group where you want to create the Azure Bot Resource
2. In the selected resource group, click Create and search for `bot`.
3. Select the option `Azure Bot`, and click `Create`
4. Provide the Bot handle, eg. `MyBot`, select Data Residency and Pricing tier
   1. Under Microsoft App ID, select `Single Tenant`
   2. In creation type select `Use existing app registration` and provide the `Application Id` obtained in the previous step

</TabItem>
<TabItem value="cli" label="Azure CLI">

To run this script, make sure you initialize the variables `resourceGroup`, `tenantId` and `appId` from the previous steps.

```bash
az bot create \
   --name $botName \
   --app-type SingleTenant \
   --appid $appId \
   --tenant-id $tenantId \
   --resource-group $resourceGroup
```

</TabItem>
</Tabs>

### Configure the Azure Bot Service resource

Once the Azure Bot Service resource has been created you can configure it. You will need to have set up a public facing endpoint so that messages from your. You can use [DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) if you wish to expose your local servers to public.

<Tabs>
<TabItem value="portal" label="Azure Portal">

1. Under `Settings/Configuration` provide the Message endpoint URL, typically it will look like: `https://myapp.mydomain.com/api/messages`
   1. When using DevTunnels for local development, use the devtunnels hosting URL with the relative path `/api/messages`
   2. When deploying to a compute instance, such as App Services, Container Apps, or in other Cloud, use the public hostname with the relative path `/api/messages`
2. In `Settings/Channels` enable the `Microsoft Teams` channel.

</TabItem>
<TabItem value="cli" label="Azure CLI">

```bash
endpointUrl=<your-devtunnels-public-url>
az bot update \
   --name $botName \
   --resource-group $resourceGroup \
   --endpoint $endpointUrl

az bot msteams create \
    --name $botName \
    --resource-group $resourceGroup
```

</TabItem>
</Tabs>

## Save the credentials to use as configuration

```bash
echo "TENANT_ID=$tenantId" > "$botName.env"
echo "CLIENT_ID=$appId" >> "$botName.env"
echo "CLIENT_SECRET=$clientSecret" >> "$botName.env"
```

## Resources

- [Teams App Publishing overview](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-publish-overview)


================================================
FILE: teams.md/docs/main/teams/core-concepts.md
================================================
---
sidebar_position: 1
summary: Understand Teams app architecture including app registration, Azure Bot Service, DevTunnel, and sideloading processes.
---

# Teams Core Concepts

When you run your agent on Teams using Microsoft 365 Agents Toolkit, several Teams-specific processes happen behind the scenes. Understanding these components will help you better debug and deploy your agents. Obviously, all these processes can be done manually, but Agents Toolkit automates them for you.

## Basic Flow

```mermaid
flowchart LR
    %% Main actors
    User([User])

    %% Teams section
    subgraph Teams ["Teams"]
        TeamsClient["Teams Client"]
        TeamsBackend["Teams Backend"]
    end

    %% Azure section
    subgraph Azure ["Azure"]
        AppReg["App Registration"]
        AzureBot["Azure Bot"]
    end

    %% Local Server section
    subgraph LocalServer ["Local Server"]
        DevTunnel["DevTunnel"]
        LocalApp["Your local application"]
    end

    %% Deployed Server section
    subgraph DeployedServer ["Deployed Server"]
        DeployedApp["Your deployed application"]
    end

    %% Define connections
    User <--> TeamsClient
    TeamsClient <--> TeamsBackend
    TeamsBackend <--> AppReg
    AppReg <--> AzureBot
    AzureBot --> LocalServer
    AzureBot --> DeployedServer
```

**Teams**

- Teams Client: User-facing agent that interacts with the user.
- Teams Backend: Part of your app package; includes a manifest with your app’s client ID.

**Azure**

- App Registration: Contains a unique client ID and secret for your app.
- Azure Bot: Connects your app to Teams; contains a pointer to your HTTPS URL.

**Local Server**

- Dev Tunnel: Public-facing HTTPS tunnel to expose your local machine.
- Local App: Your application running locally; handles events from Teams and sends responses.

**Deployed Server**

- Deployed App: Your app deployed to the cloud with a public HTTPS endpoint; also interacts with Teams.

## Core Concepts

When working with Teams, these are the key concepts. Keep in mind, this is a simplified view of the architecture.

- Teams Client: This is the Teams application where users interact with your agent. This can be the desktop app, web app, or mobile app.
- Teams Backend: This service handles all the Teams-related operations, including keeping a record of your manifest, and routing messages from your agent to the Azure bot service.
- App Registration: This is the registration of your agent in Azure. This Application Registration issues a unique client ID for your application and a client secret. This is used to authenticate your agent application with the Teams backend and other Azure services (including Graph if you are using it).
- Azure Bot Service: This is the service that handles all the bot-related operations, including routing messages from Teams to your agent and vice versa. This holds the URL to your agent application.
- DevTunnel: This is a service that creates a public facing URL to your locally running application. Azure Bot Service requires that you have a public facing https URL to your agent application.
- Local Agent Application: This is your agent application running on your local machine.
- Deployed Agent Application: This is your deployed agent which probably has a public facing URL.

## DevTunnel

[DevTunnel](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) is a critical component that makes your locally running agent accessible to Teams. When you set up a DevTunnel, it:

- Creates a secure public HTTPS endpoint that forwards to your local server
- Manages SSL certificates automatically
- Routes Teams messages and events to your local agent

:::info
DevTunnel is only one way of exposing your locally running service to the internet. Other tools like ngrok can also accomplish the same thing.
:::

## Teams App Provisioning

Before your agent can interact with Teams, it needs to be properly registered and configured. This step handles creating or updating the App Registration and creating or registering the Azure Bot instance in Azure.

### App Registration

- Creates an App ID (i.e. Client ID) in the Teams platform
- Sets up a bot registration with the Bot Framework
- Creates a client secret that your agent can use to authenticate to be able to send and receive messages. Agents Toolkit will automatically get this value and store it in the `.env` file for you.

### Azure Bot

- Creates an Azure Bot resource
- Associates the bot with your App Registration
- Configures the messaging endpoint to point to your DevTunnel (or public URL if deployed)

## Sideloading Process

Sideloading is the process of installing your agent in Teams. You are able to pass in the manifest and icons (zipped up) to the Teams client. Sideloading an application automatically makes that application available to you. You are also able to sideload the application in a Team or a Group chat. In this case, the application will be available to all members of that Team or Group chat.

:::warning
Sideloading needs to be enabled in your tenant. If this is not the case, then you will need to contact your Teams administrator to enable it.
:::

## Provisioning and Deployment

To test your app in Teams, you will at minimum need to have a provisioned Azure bot. You are likely to have other provisionied resources such as storage. Please see the Microsoft Learn [Provision cloud resources](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/provision) documentation for provisioning and deployment using Visual Studio Code and to a container service.

================================================
FILE: teams.md/docs/main/teams/enabling-in-copilot.md
================================================
---
sidebar_position: 6
summary: Learn how to enable your Teams app to work in M365 Copilot by updating the app manifest.
---

# Enabling in M365 Copilot

If you've built a Teams app or agent and want to make it available in M365 Copilot, you can easily do so by updating your app manifest. This allows users to interact with your agent through Copilot's interface.

## Prerequisites

Before enabling your app in Copilot, ensure you have:

1. A working Teams app or agent
2. Completed the app registration process (see "Running in Teams" for your language)
3. Your `BOT_ID` from the app registration

## Updating the Manifest

To enable your app in Copilot, add the following configuration to your `manifest.json` file:

```json
"copilotAgents": {
  "customEngineAgents": [
    {
      "type": "bot",
      "id": "${{BOT_ID}}"
    }
  ]
}
```

The `BOT_ID` is assigned to your agent after you have registered your application. If you followed the "Running in Teams" guide for your language, this ID should already be available in your environment configuration.

## Location of the Manifest

The manifest file is typically located in the `appPackage` folder of your project. If you used the Teams CLI to set up your project, this folder was automatically created for you.

### Example Manifest Structure

Here's how the `copilotAgents` section fits into the overall manifest structure:

```json
{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.19/MicrosoftTeams.schema.json",
  "manifestVersion": "1.19",
  "version": "1.0.0",
  "id": "${{APP_ID}}",
  "developer": {
    "name": "Your Company",
    "websiteUrl": "https://www.example.com",
    "privacyUrl": "https://www.example.com/privacy",
    "termsOfUseUrl": "https://www.example.com/terms"
  },
  "name": {
    "short": "Your App Name",
    "full": "Your Full App Name"
  },
  "description": {
    "short": "Short description",
    "full": "Full description of your app"
  },
  "icons": {
    "outline": "outline.png",
    "color": "color.png"
  },
  "accentColor": "#FFFFFF",
  "bots": [
    {
      "botId": "${{BOT_ID}}",
      "scopes": [
        "personal",
        "team",
        "groupchat"
      ],
      "supportsFiles": false,
      "isNotificationOnly": false
    }
  ],
  "copilotAgents": {
    "customEngineAgents": [
      {
        "type": "bot",
        "id": "${{BOT_ID}}"
      }
    ]
  }
}
```

## Regenerating the App Package

After updating the manifest, you need to zip the manifest and icon files into an app package:

### Using Microsoft 365 Agents Toolkit

If you're using the Microsoft 365 Agents Toolkit, the app package is automatically regenerated when you build or debug your app. The toolkit will:

1. Read your updated manifest
2. Replace variables like `${{BOT_ID}}` with actual values from your environment
3. Package the manifest and icons into a zip file
4. Deploy the updated package to Teams

### Manual Packaging

If you're manually packaging your app:

1. Ensure the `manifest.json` file is updated with the `copilotAgents` section
2. Create a zip file containing:
   - `manifest.json`
   - `color.png` (192x192 icon)
   - `outline.png` (32x32 icon)
3. Upload the zip file to Teams

## Testing in Copilot

Once you've updated and redeployed your app:

1. Open M365 Copilot in Teams or at [m365.cloud.microsoft](https://m365.cloud.microsoft/)
2. Your app should now be available as an agent option
3. Interact with your agent through the Copilot interface

## Resources

- [Convert Your Declarative Agent for Microsoft 365 Copilot to a Custom Engine Agent](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/convert-declarative-agent)
- [Teams app manifest reference](https://learn.microsoft.com/microsoftteams/platform/resources/schema/manifest-schema)


================================================
FILE: teams.md/docs/main/teams/manifest.md
================================================
---
sidebar_position: 5
summary: Learn about Teams app manifest requirements, permissions, and sideloading process for app installation.
---

# Teams Manifest

Every app or agent installed on Teams requires an app manifest json file, which provides important information and permissions to that app. When sideloading the app, you are required to provide the app manifest via zip which also includes the icons for the app.

## Manifest

There are many permissions and details that an app manifest may have added to the `manifest.json`, including the app ID, url, and much more. Please review the comprehensive documentation on the [manifest schema](https://learn.microsoft.com/microsoft-365/extensibility/schema/).

## Sideloading

Sideloading is the ability to install and test your app before it is published to your organization's app catalog. For more on sideloading, see [Upload your apps to Teams](https://learn.microsoft.com/microsoftteams/platform/concepts/deploy-and-publish/apps-upload).

To sideload, ensure the manifest includes all required information (such as the app ID, tenant details, and permissions). Place the manifest and icons at the root of a zip file.

For convenient assistance with managing your manifest and automating important functionality like sideloading, deployment, and provisioning, we recommend the [Microsoft 365 Agents Toolkit extension](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/install-teams-toolkit)) and [CLI](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/microsoft-365-agents-toolkit-cli). Please continue to the [Toolkit documentation](./configuration/agents-toolkit) to learn more.


================================================
FILE: teams.md/docs/main/teams/user-authentication/README.md
================================================
---
sidebar_position: 4
summary: Overview of user authentication in Teams SDK applications, including OAuth, SSO, and secure resource access.
---

# User Authentication

At times, agents must access secured online resources on behalf of the user, such as checking email, checking flight status, or placing an order. To enable this, the user must authenticate their identity and grant consent for the application to access these resources. This process results in the application receiving a token, which the application can then use to access the permitted resources on the user's behalf.

## How Auth Works

When building Teams applications, choosing the right authentication method is crucial for both security and user experience. Teams supports two primary authentication approaches: OAuth and Single Sign-On (SSO). While both methods serve the same fundamental purpose of validating user identity, they differ significantly in their implementation, supported identity providers, and user experience. Understanding these differences is essential for making the right choice for your application.

The following table provides a clear comparison between OAuth and SSO authentication methods, highlighting their key differences in terms of identity providers, authentication flows, and user experience.

### Single Sign-On (SSO)

Single Sign-On (SSO) in Teams provides a seamless authentication experience by leveraging a user's existing Teams identity. Once a user is logged into Teams, they can access your app without needing to sign in again. The only requirement is a one-time consent from the user, after which your app can securely retrieve their access details from Microsoft Entra ID. This consent is device-agnostic - once granted, users can access your app from any device without additional authentication steps.

When an access token expires, the app automatically initiates a token exchange flow. In this process:

1. The Teams client sends an OAuth ID token containing the user's information
2. Your app exchanges this ID token for a new access token with the previously consented scopes
3. This exchange happens silently without requiring user interaction

:::tip
Always use SSO if you're authenticating the user with Microsoft Entra ID.
:::

#### The SSO Signin Flow

The SSO signin flow involves several components working together. Here's how it works:

1. User interacts with your bot or message extension app
2. App initiates the signin process
3. If it's the first time:
   - User is shown a consent form for the requested scopes
   - Upon consent, Microsoft Entra ID issues an access token (in simple terms)
4. For subsequent interactions:
   - If token is valid, app uses it directly
   - If token expires, app silently signs the user in using the token exchange flow

This is what the SSO consent form looks like in Teams:

![SSO Consent Form](/screenshots/auth-consent-popup.png)

### OAuth

You can use a third-party OAuth Identity Provider (IdP) to authenticate your app users. The app user is registered with the identity provider, which has a trust relationship with your app. When the user attempts to log in, the identity provider validates the app user and provides them with access to your app. Microsoft Entra ID is one such third party OAuth provider. You can use other providers, such as Google, Facebook, GitHub, or any other provider.

#### The OAuth Signin Flow

The OAuth signin flow involves several components working together. Here's how it works:

1. User interacts with your bot or message extension app
2. App sends a sign-in card with a link to the OAuth provider
3. User clicks the link and is redirected to the provider's authentication page
4. User authenticates and grants consent for requested scopes
5. Provider issues an access token to your app (in simple terms)
6. App uses the token to access services on user's behalf

When an access token expires, the user will need to go through the sign-in process again. Unlike SSO, there is no automatic token exchange - the user must explicitly authenticate each time their token expires.

#### The OAuth Card

This is what the OAuth card looks like in Teams:

![OAuthCard](/screenshots/auth-explicit-signin.png)

## OAuth vs SSO - Head-to-Head Comparison

The following table provides a clear comparison between OAuth and SSO authentication methods, highlighting their key differences in terms of identity providers, authentication flows, and user experience.

| Feature                                                | OAuth                                                                              | SSO                                                                                                                                                                      |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Identity Provider                                      | Works with any OAuth provider (Microsoft Entra ID, Google, Facebook, GitHub, etc.) | Only works with Microsoft Entra ID                                                                                                                                       |
| Authentication Flow                                    | User is sent a card with a sign-in link                                            | If the user has already consented to the requested scopes in the past they will "silently" login through the token exchange flow. Otherwise user is shown a consent form |
| User Experience                                        | Requires explicit signin, and consent to scopes                                    | Re-use existing Teams credential. Only requires consent to scopes                                                                                                        |
| Conversation scopes (`personal`, `groupChat`, `teams`) | `personal` scope only                                                              | `personal` scope only                                                                                                                                                    |
| Azure Configuration differences                        | Same configuration except `Token Exchange URL` is blank                            | Same configuration except `Token Exchange URL` is set                                                                                                                    |


================================================
FILE: teams.md/docs/main/teams/user-authentication/_category_.json
================================================
{
  "label": "User Authentication Configuration",
    "collapsed": true,
    "position": 4,
}


================================================
FILE: teams.md/docs/main/teams/user-authentication/sso-setup.mdx
================================================
---
sidebar_position: 1
summary: Describes how to configure SSO in Teams
---

# SSO Setup

This section describes how to configure the Azure Bot Service (ABS), the Entra App Registration and the Teams manifest to enable Single-Sign-On (SSO) for your Teams app.

## Create the Entra App Registration

You need an Entra ID App Registration to configure the OAuth Connection in Azure Bot Service. This can be the same EntraId app registration you used to configure your ABS resource or a new App created just for this purpose. You can create the App Registration from the Azure portal, or the CLI, the next list summarizes the creation steps from the portal.

1. Use the existing App registration, or Create a new App registration from the [Entra Id](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps) section in the Azure portal. Now you have an Application Id (also known as Client ID) and a Tenant Id.
2. Provide a name for the app registration, select SingleTenant, and for the Redirect URI select the platform Web and add the value `https://token.botframework.com/.auth/web/redirect`

![Entra new app](/screenshots/entra-new-app.png)

3. Add a new client secret. From `Certificates & secrets`, select `Client secrets` and add `New client secret`. Take note of the secret as you will need the value later on this guide.

![Entra client secret](/screenshots/entra-client-secret.png)

4. Configure the API. From `Expose an API`,  Click `Add` to Application ID URI and accept the default value that will look like `api://<Your-Application-Id>`. Add the scope `access_as_user` and select who can _consent_.

![Entra oauth scopes](/screenshots/entra-oauth-scopes.png)

5. Authorize the client applications for SSO. To enable the Teams clients, desktop and web, to perform the SSO flow you must add the next client applications to the scope defined before: Teams Desktop `1fec8e78-bce4-4aaf-ab1b-5451cc387264` and Teams Web `5e3ce6c0-2b1f-4285-8d4b-75ee78787346`

![Entra oauth authorize client app](/screenshots/entra-authorize-clientapp.png)

### Configure the Entra App Registration with the CLI

```bash
#!/bin/bash

az ad app update --id $appId --web-redirect-uris "https://token.botframework.com/.auth/web/redirect"
az ad app update --id $appId --identifier-uris "api://$appId"
# TODO: add oauthpermission settings and client applications.
```

## Create the OAuth connection in Azure Bot Service

You need to add a new OAuth connection to your Azure Bot Service resource.

1. From the Bot service resource in the Azure Portal, navigate to `Settings/Configuration` and `Add OAuth Connection settings`.
2. Provide a name for your connection e.g. `graph`, and select the _Service Provider_ `Azure Active Directory v2`
3. Populate the `TenantId`/`ClientId`/`ClientSecret` from the values obtained in the previous section steps 2 and 3. Configure the Token Exchange URL with the Application ID URI configured in step 4, and add the Scopes you need e.g. `User.Read`

![ABS OAuth connection](/screenshots/abs-oauth-connection.png)

### Create the OAuth connection using the Azure CLI

```bash
#!/bin/bash

az bot authsetting create \
  --resource-group $resourceGroup \
  --name $botName \
  -c "graph" \
  --client-id $appId \
  --client-secret $clientSecret \
  --provider-scope-string "User.Read" \
  --service "Aadv2" \
  --parameters "clientId=$appId" "clientSecret=$clientSecret" "tenantId=$tenantId" "tokenExchangeUrl=api://$appId"
```


## Configure the App Manifest

The Teams application manifest needs to be updated to reflect the settings configure above, with the `Application Id` and `Application ID URI`, if not using `devtunnels`, replace the valid domain with the domain hosting your application. 

```json
"validDomains": [
    "*.devtunnels.ms",
    "*.botframework.com",
 ],
 "webApplicationInfo": {
    "id": "<Your-Application-Id>",
    "resource": "api://<Your-Application-Id>"
  }
```

## Troubleshooting

If you encounter SSO errors, see the [Troubleshooting](troubleshooting-sso) guide for common issues and solutions.



================================================
FILE: teams.md/docs/main/teams/user-authentication/troubleshooting-sso.mdx
================================================
---
sidebar_position: 2
title: Troubleshooting
summary: Common SSO errors and how to resolve them
---

import LangLink from '@site/src/components/LangLink';

# SSO Troubleshooting

When SSO fails, Teams sends a `signin/failure` invoke activity to your bot with a `code` and `message` describing the error. The SDK's default handler logs a warning with these details.

## Failure codes

| Code | Silent | Description |
|------|--------|-------------|
| `installappfailed` | No | Failed to install the app in the user's personal scope (group chat SSO flow). |
| `authrequestfailed` | No | The SSO auth request failed after app installation. |
| `installedappnotfound` | Yes | The bot app is not installed for the user or group chat. *(most common)* |
| `invokeerror` | Yes | A generic error occurred during the SSO invoke flow. |
| `resourcematchfailed` | Yes | The token exchange resource URI on the OAuthCard does not match the Application ID URI in the Entra app registration's "Expose an API" section. *(common)* |
| `oauthcardnotvalid` | Yes | The bot's OAuthCard could not be parsed. |
| `tokenmissing` | Yes | AAD token acquisition failed. |

"Silent" failures produce no user-facing feedback in the Teams client — the user sees nothing and sign-in simply doesn't complete. "Non-silent" failures occur during the group chat SSO flow where the user is shown an install/auth card.

:::note
The `userconsentrequired` and `interactionrequired` codes are handled by the Teams client via the OAuth card fallback flow and do not typically reach the bot.
:::

## `resourcematchfailed`

If you see a warning in your app logs like:

> Sign-in failed for user "..." in conversation "...": resourcematchfailed -- Resource match failed

This means Teams attempted the SSO token exchange but failed because the token exchange resource URI does not match your Entra app registration. To fix this:

1. **Verify "Expose an API"** in your Entra app registration: the Application ID URI must be set (typically `api://<Your-Application-Id>`)
2. **Verify the `access_as_user` scope** is defined under "Expose an API"
3. **Verify pre-authorized client applications** include the Teams Desktop (`1fec8e78-bce4-4aaf-ab1b-5451cc387264`) and Teams Web (`5e3ce6c0-2b1f-4285-8d4b-75ee78787346`) client IDs
4. **Verify the Token Exchange URL** in your Azure Bot OAuth connection matches the Application ID URI exactly
5. **Verify the `webApplicationInfo.resource`** in your Teams app manifest matches the Application ID URI

:::tip
If you don't need SSO and only want standard OAuth (sign-in button), leave the **Token Exchange URL** blank in your OAuth connection settings.
:::

To handle `signin/failure` programmatically in your app, see <LangLink to="in-depth-guides/user-authentication#handling-sign-in-failures">Handling Sign-In Failures</LangLink> in the User Authentication guide.


================================================
FILE: teams.md/docs/main/welcome.mdx
================================================
---
sidebar_position: 0
summary: Welcome guide to Teams SDK, covering the quickstart process and how to build agents and applications for Microsoft Teams.
llms: ignore
---

import LangLink from '@site/src/components/LangLink';

# 👋 Welcome

Teams SDK is a suite of packages used to develop on Microsoft Teams. Rebuilt from the ground up with improved developer experience in mind, it's never been easier to build powerful agents and applications for the hundreds of millions Microsoft Teams users.

## Quickstart

The Teams CLI makes it easy to bootstrap your first agent. Using `npx @microsoft/teams.cli` you can get started using these commands:

**TypeScript:**

```bash
npx @microsoft/teams.cli@latest new typescript quote-agent --template echo
```

**C#:**

```bash
npx @microsoft/teams.cli@latest new csharp quote-agent --template echo
```

**Python:**

```bash
npx @microsoft/teams.cli@latest new python quote-agent --template echo
```

## Overview

Microsoft Teams has a robust developer ecosystem with a broad suite of capabilities, now unified via Teams SDK. Whether you are building <LangLink to="in-depth-guides/ai">AI-powered agents</LangLink>, <LangLink to="in-depth-guides/message-extensions">message extensions</LangLink>, embedded web applications, or Graph, Teams SDK has you covered.

## ⭐ What's new?

### Streamlined Developer Experience

We’ve refined the developer experience so you can concentrate on building your app’s logic — not wrestling with integrations.

### Effortless Integration

We’ve simplified complex integration workflows to help you deliver a richer, more seamless user experience.

### Accelerate Your Workflow

Get your application up and running in under 30 seconds with our lightning-fast CLI—so you can spend more time on what really matters.

## 🔎 Navigation Tips

We encourage you to use the left sidebar to navigate to your desired section.

Can't find what you're searching for? Use the search button above.


================================================
FILE: teams.md/docs/main/why.md
================================================
---
sidebar_position: 1
summary: Explanation of why an SDK is beneficial for building Teams agent applications, covering event handling and proactive messaging patterns.
llms: ignore
---

# Why An SDK?

Before getting into the basics, it's important to understand how an SDK can be helpful when building an agent application. For this, it's a good exercise to understand the basic messaging and event flow of a Teams agent application.

---

An agent application is mainly able to do two things:

- Listen to events and respond to them
- Proactively send messages to the user

```mermaid
flowchart LR
    Teams([Teams])
    InputEvents["Input Events"]
    OutputEvents["Output Events"]
    Application(["Your application"])

    Teams --> InputEvents
    OutputEvents --> Teams
    InputEvents --> Application
    Application --> OutputEvents

    %% Styling for dark/light compatibility
    style Teams fill:#2E86AB,stroke:#1B4F72,stroke-width:2px,color:#ffffff
    style Application fill:#28B463,stroke:#1D8348,stroke-width:2px,color:#ffffff
```

To do this, we already need a few components:

1. A public facing URL to our agent application - This is so that the Teams backend knows where to send messages to when an interesting event happens.
2. A unique identifier for our agent application - Teams doesn't like to pass around this URL everywhere. Instead it hides this information behind a unique ID. This way, if your URL changes, all you need to do is update the URL and keep the ID the same.
3. A way to authenticate to and from the Teams backend - This public facing URL may get hit in many different ways. We need some protections to make sure that the only messages that reach our main application are authenticated.

```mermaid
flowchart LR
    Start("Start")
    Teams([Teams])
    PublicFacingUrl["Public Facing Endpoint"]
    TeamsURL["Teams Endpoint"]
    AuthInput["Authentication"]
    AuthOutput["Authentication"]
    InputEvents["Input Events"]
    OutputEvents["Output Events"]
    Application(["Your application logic"])

    Start --> Teams
    subgraph TeamsEcosystem["Teams Ecosystem"]
        Teams --> InputEvents
    end
    subgraph App["Application with Unique Id"]
        InputEvents --> PublicFacingUrl
        PublicFacingUrl --> AuthInput --> Application
        Application -.-> AuthOutput
        AuthOutput -.-> OutputEvents
    end
    subgraph TeamsEcosystem["Teams Ecosystem"]
        OutputEvents --> TeamsURL --> Teams
    end

    %% Styling for dark/light compatibility
    style Teams fill:#2E86AB,stroke:#1B4F72,stroke-width:2px,color:#ffffff
    style Application fill:#28B463,stroke:#1D8348,stroke-width:2px,color:#ffffff
```

Next, once a request is successfully authenticated, there is a _slew_ of possible types of events that can be sent to your agent application. User messages, user reactions, installation events, Adaptive Card actions, dialog actions, and more. All of these get to your application through a single public door - the public facing URL. Not only this, but different types of events may expect a particular type of response back. For example, a message event may expect a text response or an Adaptive Card response, while a reaction event may not expect a response at all.

Now, it's possible for your own application to handle all the nuances with these events, but that would be a lot of work, and a lot of boilerplate code. Think, a gigantic switch statement at the very least.

```mermaid
block-beta
    columns 5
    block:InputEventsGroup:2
        columns 1
        InputEvents("Input Events"):1
        block:group2:1
            columns 2
            UserMessaged
            UserReacted
            FormSubmitted
            Etc1["..."]
        end
    end
    space:1
    block:AppHandlersGroup:2
        columns 1
        Handlers("Application Handlers"):1
        block:group4:1
            columns 2
            UserMessageH["User Messaged<br/>handler"]
            UserReactedH["User Reacted<br/>handler"]
            FormSubmittedH["Form Submitted<br/>handler"]
            Etc2["..."]
        end
    end
    InputEventsGroup --> AppHandlersGroup
```

Next, if you wanted to send messages to the user, you would need to make sure each call to the Teams backend is authenticated appropriately for your application.

If your application wanted additional data from [Microsoft Graph](https://learn.microsoft.com/en-us/graph/overview), you would need to authenticate to that as well. Additionally, if you wanted the _user_ to authenticate and query Graph on their behalf, you would have to set up a solution to do the OAuth flow as well. For these complex flows, Teams offers a solution, but you must adhere to specific protocols and patterns to facilitate them.

```mermaid
block-beta
    columns 4
    space:2
    block:userAuth:2
        columns 4
        Graph:1
        Github:1
        Google:1
        Etc["..."]:1
        space:4
        UserAuth["User OAuth/SSO"]:4
        UserAuth-->Graph
        UserAuth-->Github
        UserAuth-->Google
        UserAuth-->Etc
    end
    block:events:2
        columns 2
        blockArrowInput<["InputEvents"]>(right)
        InputAuthentication["Input Auth"]
        blockArrowOutput<["OutputEvents"]>(left)
        OutputAuthentication["Output Auth"]
    end

    Application:2

    style Application fill:#28B463,stroke:#1D8348,stroke-width:2px,color:#ffffff
```

As you can see, there are a lot of moving parts to building a Teams agent application. This is where the SDK comes in. The SDK abstracts away all of the boilerplate code and provides you with a simple interface to work with. It handles all the authentication, routing, and event handling for you, so you can focus on building your application.


================================================
FILE: teams.md/docusaurus.config.ts
================================================
import type * as Preset from '@docusaurus/preset-classic';
import type { Config } from '@docusaurus/types';
import path from 'node:path';
import { themes as prismThemes } from 'prism-react-renderer';

// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
const baseUrl = '/teams-sdk/';
const config: Config = {
    title: 'Teams SDK',
    favicon: 'img/msft-logo-48x48.png',

    // Set the production url of your site here
    url: 'https://microsoft.github.io/',
    // Set the /<baseUrl>/ pathname under which your site is served
    // For GitHub pages deployment, it is often '/<projectName>/'
    baseUrl,

    // GitHub pages deployment config.
    // If you aren't using GitHub pages, you don't need these.
    organizationName: 'microsoft', // Usually your GitHub org/user name.
    projectName: baseUrl, // Usually your repo name.

    onBrokenLinks: 'throw',

    // Even if you don't use internationalization, you can use this field to set
    // useful metadata like html lang. For example, if your site is Chinese, you
    // may want to replace "en" with "zh-Hans".
    i18n: {
        defaultLocale: 'en',
        locales: ['en'],
    },

    markdown: {
        mermaid: true,
        hooks: {
            onBrokenMarkdownLinks: 'throw',
        },
    },
    headTags: [
        {
            tagName: 'link',
            attributes: {
                rel: 'llms.txt',
                href: 'https://microsoft.github.io/teams-sdk/llms_docs/llms.txt'
            }
        }
    ],
    scripts: [path.join(baseUrl, '/scripts/clarity.js')],

    presets: [
        [
            'classic',
            {
                blog: false,
                docs: {
                    routeBasePath: '/',
                    path: 'docs/main',
                    sidebarPath: './sidebars.ts',
                    sidebarCollapsed: false,
                    editUrl: 'https://github.com/microsoft/teams-sdk/tree/main/teams.md/',
                    // Temporary exclude until generate-LLMs script is fully tested
                    exclude: ['**/LLMs.md'],
                },
                pages: {
                    exclude: ['**/templates/**'],
                },
                theme: {
                    customCss: ['./src/css/custom.css', './src/css/code-blocks.css'],
                },
            } satisfies Preset.Options,
        ],
    ],

    themes: [
        '@docusaurus/theme-mermaid',
        [
            require.resolve('@easyops-cn/docusaurus-search-local'),
            /** @type {import("@easyops-cn/docusaurus-search-local").PluginOptions} */
            {
                hashed: true,
                language: ['en'],
                docsRouteBasePath: ['/', '/typescript', '/csharp', '/python'],
                indexDocs: true,
                indexPages: true,
                highlightSearchTermsOnTargetPage: true,
            },
        ],
    ],
    themeConfig: {
        colorMode: {
            respectPrefersColorScheme: true,
        },
        navbar: {
            title: 'Teams SDK',
            hideOnScroll: true,
            logo: {
                alt: 'Teams SDK',
                src: 'img/teams.png',
            },
            items: [
                {
                    href: 'https://github.com/microsoft/teams-sdk/tree/main',
                    position: 'right',
                    className: 'header-github-link',
                },
            ],
        },
        footer: {
            style: 'dark',
            links: [
                {
                    title: 'Docs',
                    items: [
                        {
                            label: 'Getting Started',
                            to: '/',
                        },
                        {
                            label: 'TypeScript',
                            to: '/typescript/getting-started',
                        },
                        {
                            label: 'C#',
                            to: '/csharp/getting-started',
                        },
                        {
                            label: 'Python',
                            to: '/python/getting-started',
                        },
                        {
                            label: 'Privacy policy',
                            to: '/privacy',
                        },
                    ],
                },
                {
                    title: 'More',
                    items: [
                        {
                            label: 'GitHub',
                            href: 'https://github.com/microsoft/teams-sdk/tree/main',
                        },
                        {
                            label: 'Contributing',
                            href: 'https://github.com/microsoft/teams-sdk/blob/main/CONTRIBUTING.md',
                        },
                        {
                            label: 'Blog',
                            href: 'https://devblogs.microsoft.com/microsoft365dev/announcing-the-updated-teams-ai-library-and-mcp-support/',
                        },
                        {
                            label: 'Teams agent accelerator templates',
                            href: 'https://microsoft.github.io/teams-agent-accelerator-templates/',
                        },
                    ],
                },
            ],
            copyright: `Copyright © ${new Date().getFullYear()} Microsoft Corporation. All rights reserved.`,
        },
        prism: {
            theme: prismThemes.dracula,
            darkTheme: prismThemes.vsDark,
            magicComments: [
                {
                    className: 'theme-code-block-highlighted-line',
                    line: 'highlight-next-line',
                    block: {
                        start: 'highlight-start',
                        end: 'highlight-end',
                    },
                },
                {
                    className: 'code-block-error-line',
                    line: 'highlight-error-line',
                    block: {
                        start: 'highlight-error-start',
                        end: 'highlight-error-end',
                    },
                },
                {
                    className: 'code-block-success-line',
                    line: 'highlight-success-line',
                    block: {
                        start: 'highlight-success-start',
                        end: 'highlight-success-end',
                    },
                },
            ],
            additionalLanguages: [
                'typescript',
                'javascript',
                'csharp',
                'python',
                'bash',
                'markdown',
                'json',
            ],
        },
        announcementBar: {
            id: 'teams-sdk-rename',
            content: 'We have been renamed to Teams SDK! 🎉 🥳',
            isCloseable: true,
            backgroundColor: '#515cc6',
            textColor: '#fff'
        },
    } satisfies Preset.ThemeConfig,
};

export default config;


================================================
FILE: teams.md/i18n/en/code.json
================================================
{
  "theme.ErrorPageContent.title": {
    "message": "This page crashed.",
    "description": "The title of the fallback page when the page crashed"
  },
  "theme.BackToTopButton.buttonAriaLabel": {
    "message": "Scroll back to top",
    "description": "The ARIA label for the back to top button"
  },
  "theme.blog.archive.title": {
    "message": "Archive",
    "description": "The page & hero title of the blog archive page"
  },
  "theme.blog.archive.description": {
    "message": "Archive",
    "description": "The page & hero description of the blog archive page"
  },
  "theme.blog.paginator.navAriaLabel": {
    "message": "Blog list page navigation",
    "description": "The ARIA label for the blog pagination"
  },
  "theme.blog.paginator.newerEntries": {
    "message": "Newer entries",
    "description": "The label used to navigate to the newer blog posts page (previous page)"
  },
  "theme.blog.paginator.olderEntries": {
    "message": "Older entries",
    "description": "The label used to navigate to the older blog posts page (next page)"
  },
  "theme.blog.post.paginator.navAriaLabel": {
    "message": "Blog post page navigation",
    "description": "The ARIA label for the blog posts pagination"
  },
  "theme.blog.post.paginator.newerPost": {
    "message": "Newer post",
    "description": "The blog post button label to navigate to the newer/previous post"
  },
  "theme.blog.post.paginator.olderPost": {
    "message": "Older post",
    "description": "The blog post button label to navigate to the older/next post"
  },
  "theme.tags.tagsPageLink": {
    "message": "View all tags",
    "description": "The label of the link targeting the tag list page"
  },
  "theme.colorToggle.ariaLabel": {
    "message": "Switch between dark and light mode (currently {mode})",
    "description": "The ARIA label for the navbar color mode toggle"
  },
  "theme.colorToggle.ariaLabel.mode.dark": {
    "message": "dark mode",
    "description": "The name for the dark color mode"
  },
  "theme.colorToggle.ariaLabel.mode.light": {
    "message": "light mode",
    "description": "The name for the light color mode"
  },
  "theme.docs.breadcrumbs.navAriaLabel": {
    "message": "Breadcrumbs",
    "description": "The ARIA label for the breadcrumbs"
  },
  "theme.docs.DocCard.categoryDescription.plurals": {
    "message": "1 item|{count} items",
    "description": "The default description for a category card in the generated index about how many items this category includes"
  },
  "theme.docs.paginator.navAriaLabel": {
    "message": "Docs pages",
    "description": "The ARIA label for the docs pagination"
  },
  "theme.docs.paginator.previous": {
    "message": "Previous",
    "description": "The label used to navigate to the previous doc"
  },
  "theme.docs.paginator.next": {
    "message": "Next",
    "description": "The label used to navigate to the next doc"
  },
  "theme.docs.tagDocListPageTitle.nDocsTagged": {
    "message": "One doc tagged|{count} docs tagged",
    "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
  },
  "theme.docs.tagDocListPageTitle": {
    "message": "{nDocsTagged} with \"{tagName}\"",
    "description": "The title of the page for a docs tag"
  },
  "theme.docs.versionBadge.label": {
    "message": "Version: {versionLabel}"
  },
  "theme.docs.versions.unreleasedVersionLabel": {
    "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.",
    "description": "The label used to tell the user that he's browsing an unreleased doc version"
  },
  "theme.docs.versions.unmaintainedVersionLabel": {
    "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.",
    "description": "The label used to tell the user that he's browsing an unmaintained doc version"
  },
  "theme.docs.versions.latestVersionSuggestionLabel": {
    "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).",
    "description": "The label used to tell the user to check the latest version"
  },
  "theme.docs.versions.latestVersionLinkLabel": {
    "message": "latest version",
    "description": "The label used for the latest version suggestion link label"
  },
  "theme.common.editThisPage": {
    "message": "Edit this page",
    "description": "The link label to edit the current page"
  },
  "theme.common.headingLinkTitle": {
    "message": "Direct link to {heading}",
    "description": "Title for link to heading"
  },
  "theme.lastUpdated.atDate": {
    "message": " on {date}",
    "description": "The words used to describe on which date a page has been last updated"
  },
  "theme.lastUpdated.byUser": {
    "message": " by {user}",
    "description": "The words used to describe by who the page has been last updated"
  },
  "theme.lastUpdated.lastUpdatedAtBy": {
    "message": "Last updated{atDate}{byUser}",
    "description": "The sentence used to display when a page has been last updated, and by who"
  },
  "theme.navbar.mobileVersionsDropdown.label": {
    "message": "Versions",
    "description": "The label for the navbar versions dropdown on mobile view"
  },
  "theme.NotFound.title": {
    "message": "Page Not Found",
    "description": "The title of the 404 page"
  },
  "theme.admonition.caution": {
    "message": "caution",
    "description": "The default label used for the Caution admonition (:::caution)"
  },
  "theme.admonition.danger": {
    "message": "danger",
    "description": "The default label used for the Danger admonition (:::danger)"
  },
  "theme.admonition.info": {
    "message": "info",
    "description": "The default label used for the Info admonition (:::info)"
  },
  "theme.admonition.note": {
    "message": "note",
    "description": "The default label used for the Note admonition (:::note)"
  },
  "theme.admonition.tip": {
    "message": "tip",
    "description": "The default label used for the Tip admonition (:::tip)"
  },
  "theme.admonition.warning": {
    "message": "warning",
    "description": "The default label used for the Warning admonition (:::warning)"
  },
  "theme.tags.tagsListLabel": {
    "message": "Tags:",
    "description": "The label alongside a tag list"
  },
  "theme.AnnouncementBar.closeButtonAriaLabel": {
    "message": "Close",
    "description": "The ARIA label for close button of announcement bar"
  },
  "theme.blog.sidebar.navAriaLabel": {
    "message": "Blog recent posts navigation",
    "description": "The ARIA label for recent posts in the blog sidebar"
  },
  "theme.CodeBlock.copied": {
    "message": "Copied",
    "description": "The copied button label on code blocks"
  },
  "theme.CodeBlock.copyButtonAriaLabel": {
    "message": "Copy code to clipboard",
    "description": "The ARIA label for copy code blocks button"
  },
  "theme.CodeBlock.copy": {
    "message": "Copy",
    "description": "The copy button label on code blocks"
  },
  "theme.CodeBlock.wordWrapToggle": {
    "message": "Toggle word wrap",
    "description": "The title attribute for toggle word wrapping button of code block lines"
  },
  "theme.DocSidebarItem.expandCategoryAriaLabel": {
    "message": "Expand sidebar category '{label}'",
    "description": "The ARIA label to expand the sidebar category"
  },
  "theme.DocSidebarItem.collapseCategoryAriaLabel": {
    "message": "Collapse sidebar category '{label}'",
    "description": "The ARIA label to collapse the sidebar category"
  },
  "theme.NavBar.navAriaLabel": {
    "message": "Main",
    "description": "The ARIA label for the main navigation"
  },
  "theme.navbar.mobileLanguageDropdown.label": {
    "message": "Languages",
    "description": "The label for the mobile language switcher dropdown"
  },
  "theme.TOCCollapsible.toggleButtonLabel": {
    "message": "On this page",
    "description": "The label used by the button on the collapsible TOC component"
  },
  "theme.NotFound.p1": {
    "message": "We could not find what you were looking for.",
    "description": "The first paragraph of the 404 page"
  },
  "theme.NotFound.p2": {
    "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.",
    "description": "The 2nd paragraph of the 404 page"
  },
  "theme.blog.post.readMore": {
    "message": "Read more",
    "description": "The label used in blog post item excerpts to link to full blog posts"
  },
  "theme.blog.post.readMoreLabel": {
    "message": "Read more about {title}",
    "description": "The ARIA label for the link to full blog posts from excerpts"
  },
  "theme.blog.post.readingTime.plurals": {
    "message": "One min read|{readingTime} min read",
    "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
  },
  "theme.docs.breadcrumbs.home": {
    "message": "Home page",
    "description": "The ARIA label for the home page in the breadcrumbs"
  },
  "theme.docs.sidebar.collapseButtonTitle": {
    "message": "Collapse sidebar",
    "description": "The title attribute for collapse button of doc sidebar"
  },
  "theme.docs.sidebar.collapseButtonAriaLabel": {
    "message": "Collapse sidebar",
    "description": "The title attribute for collapse button of doc sidebar"
  },
  "theme.docs.sidebar.navAriaLabel": {
    "message": "Docs sidebar",
    "description": "The ARIA label for the sidebar navigation"
  },
  "theme.docs.sidebar.closeSidebarButtonAriaLabel": {
    "message": "Close navigation bar",
    "description": "The ARIA label for close button of mobile sidebar"
  },
  "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
    "message": "← Back to main menu",
    "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
  },
  "theme.docs.sidebar.toggleSidebarButtonAriaLabel": {
    "message": "Toggle navigation bar",
    "description": "The ARIA label for hamburger menu button of mobile navigation"
  },
  "theme.docs.sidebar.expandButtonTitle": {
    "message": "Expand sidebar",
    "description": "The ARIA label and title attribute for expand button of doc sidebar"
  },
  "theme.docs.sidebar.expandButtonAriaLabel": {
    "message": "Expand sidebar",
    "description": "The ARIA label and title attribute for expand button of doc sidebar"
  },
  "theme.blog.post.plurals": {
    "message": "One post|{count} posts",
    "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
  },
  "theme.blog.tagTitle": {
    "message": "{nPosts} tagged with \"{tagName}\"",
    "description": "The title of the page for a blog tag"
  },
  "theme.blog.author.pageTitle": {
    "message": "{authorName} - {nPosts}",
    "description": "The title of the page for a blog author"
  },
  "theme.blog.authorsList.pageTitle": {
    "message": "Authors",
    "description": "The title of the authors page"
  },
  "theme.blog.authorsList.viewAll": {
    "message": "View all authors",
    "description": "The label of the link targeting the blog authors page"
  },
  "theme.blog.author.noPosts": {
    "message": "This author has not written any posts yet.",
    "description": "The text for authors with 0 blog post"
  },
  "theme.contentVisibility.unlistedBanner.title": {
    "message": "Unlisted page",
    "description": "The unlisted content banner title"
  },
  "theme.contentVisibility.unlistedBanner.message": {
    "message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.",
    "description": "The unlisted content banner message"
  },
  "theme.contentVisibility.draftBanner.title": {
    "message": "Draft page",
    "description": "The draft content banner title"
  },
  "theme.contentVisibility.draftBanner.message": {
    "message": "This page is a draft. It will only be visible in dev and be excluded from the production build.",
    "description": "The draft content banner message"
  },
  "theme.ErrorPageContent.tryAgain": {
    "message": "Try again",
    "description": "The label of the button to try again rendering when the React error boundary captures an error"
  },
  "theme.common.skipToMainContent": {
    "message": "Skip to main content",
    "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
  },
  "theme.tags.tagsPageTitle": {
    "message": "Tags",
    "description": "The title of the tag list page"
  }
}


================================================
FILE: teams.md/i18n/en/docusaurus-plugin-content-docs/current.json
================================================
{
  "version.label": {
    "message": "Next",
    "description": "The label for version current"
  }
}


================================================
FILE: teams.md/i18n/en/docusaurus-plugin-content-docs-csharp/current.json
================================================
{
  "version.label": {
    "message": "Next",
    "description": "The label for version current"
  }
}


================================================
FILE: teams.md/i18n/en/docusaurus-plugin-content-docs-typescript/current.json
================================================
{
  "version.label": {
    "message": "Next",
    "description": "The label for version current"
  },
  "sidebar.default.category.In Depth Guides": {
    "message": "In Depth Guides",
    "description": "The label for category In Depth Guides in sidebar default"
  },
  "sidebar.typescript.category.In Depth Guides": {
    "message": "In Depth Guides",
    "description": "The label for category In Depth Guides in sidebar typescript"
  },
  "sidebar.csharp.category.In Depth Guides": {
    "message": "In Depth Guides",
    "description": "The label for category In Depth Guides in sidebar csharp"
  },
  "sidebar.python.category.In Depth Guides": {
    "message": "In Depth Guides",
    "description": "The label for category In Depth Guides in sidebar python"
  }
}


================================================
FILE: teams.md/i18n/en/docusaurus-theme-classic/footer.json
================================================
{
  "link.title.Docs": {
    "message": "Docs",
    "description": "The title of the footer links column with title=Docs in the footer"
  },
  "link.title.More": {
    "message": "More",
    "description": "The title of the footer links column with title=More in the footer"
  },
  "link.item.label.Getting Started": {
    "message": "Getting Started",
    "description": "The label of footer link with label=Getting Started linking to /"
  },
  "link.item.label.Blog": {
    "message": "Blog",
    "description": "The label of footer link with label=Blog linking to https://devblogs.microsoft.com/microsoft365dev/announcing-the-updated-teams-ai-library-and-mcp-support/"
  },
  "link.item.label.GitHub": {
    "message": "GitHub",
    "description": "The label of footer link with label=GitHub linking to https://github.com/microsoft/teams-sdk/tree/main"
  },
  "copyright": {
    "message": "Copyright © 2025 Microsoft Corporation. All rights reserved.",
    "description": "The footer copyright"
  }
}


================================================
FILE: teams.md/i18n/en/docusaurus-theme-classic/navbar.json
================================================
{
  "title": {
    "message": "Teams SDK",
    "description": "The title in the navbar"
  },
  "logo.alt": {
    "message": "Teams SDK",
    "description": "The alt text of navbar logo"
  },
  "item.label.Typescript": {
    "message": "Typescript",
    "description": "Navbar item with label Typescript"
  },
  "item.label.C#": {
    "message": "C#",
    "description": "Navbar item with label C#"
  },
  "item.label.Python": {
    "message": "Python",
    "description": "Navbar item with label Python"
  }
}


================================================
FILE: teams.md/package.json
================================================
{
  "name": "teams-md",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "docusaurus": "docusaurus",
    "start": "concurrently --kill-others \"npm run generate:docs:watch\" \"docusaurus start\"",
    "start:simple": "docusaurus start",
    "prebuild": "npm run generate:docs",
    "build": "docusaurus build",
    "swizzle": "docusaurus swizzle",
    "deploy": "docusaurus deploy",
    "clear": "docusaurus clear",
    "serve": "docusaurus serve",
    "write-heading-ids": "docusaurus write-heading-ids",
    "typecheck": "tsc",
    "generate:docs": "tsx scripts/generate-language-docs.ts",
    "generate:docs:watch": "tsx scripts/generate-language-docs.ts --watch",
    "generate:llms": "tsx scripts/generate-llms-txt.ts",
    "scaffold": "node src/scripts/scaffold.js"
  },
  "dependencies": {
    "@docusaurus/core": "^3.9.2",
    "@docusaurus/preset-classic": "^3.9.2",
    "@docusaurus/theme-mermaid": "^3.9.2",
    "@easyops-cn/docusaurus-search-local": "^0.49.2",
    "@mdx-js/react": "^3.0.0",
    "clsx": "^2.0.0",
    "prism-react-renderer": "^2.3.0",
    "react": "^19.2.1",
    "react-dom": "^19.2.1",
    "react-json-view-lite": "^2.4.1"
  },
  "devDependencies": {
    "@docusaurus/module-type-aliases": "^3.9.2",
    "@docusaurus/tsconfig": "^3.9.2",
    "@docusaurus/types": "^3.9.2",
    "@types/chokidar": "^1.7.5",
    "@types/js-yaml": "^4.0.9",
    "chokidar": "^3.6.0",
    "concurrently": "^9.2.1",
    "js-yaml": "^4.1.1",
    "json-stable-stringify": "^1.3.0",
    "tsx": "^4.20.6",
    "typescript": "~5.6.2"
  },
  "browserslist": {
    "production": [
      ">0.5%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 3 chrome version",
      "last 3 firefox version",
      "last 5 safari version"
    ]
  },
  "engines": {
    "node": ">=20.0"
  }
}


================================================
FILE: teams.md/scripts/generate-language-docs.ts
================================================
#!/usr/bin/env node

import * as fs from 'fs';
import * as path from 'path';
import * as chokidar from 'chokidar';
import * as yaml from 'js-yaml';
import stringify from 'json-stable-stringify';

import { FrontmatterParser, FRONTMATTER_REGEX } from './lib/frontmatter-parser';
import {
  LANGUAGES,
  LANGUAGE_NAMES,
  type Language,
  type LanguageAvailabilityMap,
} from '../src/constants/languages';
import normalizePath from '../src/utils/normalizePath';
import readFileUtf8Normalized from '../src/utils/readFileUtf8Normalized';

const missingPagesManifest: LanguageAvailabilityMap = {};
const contentGapsManifest: { [templatePath: string]: { [sectionName: string]: Language[] } } = {};

const TEMPLATES_DIR = path.join(__dirname, '..', 'src', 'pages', 'templates');
const FRAGMENTS_DIR = path.join(__dirname, '..', 'src', 'components', 'include');

const DOCS_BASE = path.join(__dirname, '..', 'docs', 'main');

const isProduction = process.env.NODE_ENV === 'production';

// Track all include files that are actually referenced by templates
// Languages excluded from a template via frontmatter will not be processed
const processedIncludeFiles = new Set<string>();

// For sections in an *.mdx file that is applicable to one or two languages, but not all three.
// This is an intentional way of differentiating from missing sections in documentation that haven't been written yet.
const NOT_APPLICABLE_REGEX = /^(not applicable|n\/a)\s*$/i;

// Notation in *.incl.md files for sections to be added into the *.mdx
const SECTION_REGEX = (sectionName: string) =>
  new RegExp(`<!--\\s*${sectionName}\\s*-->\\s*([\\s\\S]*?)(?=<!--\\s*[\\w-]+\\s*-->|$)`, 'i');

// Regex to find LanguageInclude tags (supports both section and content props)
const LANGUAGE_INCLUDE_REGEX = /<LanguageInclude\s+(?:section="([^"]+)"|content=\{(\{[^}]+\})\})\s*\/>/g;

const languagePattern = LANGUAGES.join('|');
const LANGUAGE_INCL_FILENAME_REGEX = new RegExp(`^(${languagePattern})\\.incl\\.md$`);

/**
 * Extract a section from markdown content using HTML comment markers
 * - null: section not found (no matching HTML comment)
 * - '': section found but marked as N/A (intentionally empty)
 * - 'EMPTY_SECTION': section found but has no content (should show error in dev)
 * - string: section content
 */
function extractSection(markdown: string, sectionName: string): string | null {
  if (!markdown) {
    return 'EMPTY_SECTION';
  }

  const match = markdown.match(SECTION_REGEX(sectionName));

  // Section not found
  if (!match) {
    return null;
  }

  const content = match[1].trim();

  // Content not applicable
  if (NOT_APPLICABLE_REGEX.test(content)) {
    return '';
  }

  // Section exists but has no content
  if (content === '') {
    return 'EMPTY_SECTION';
  }

  return content;
}

/**
 * Given a template path and language, return the include file path for that language.
 */
function getIncludeFilePath(templatePath: string, language: Language): string {
  const relativePath = path.relative(TEMPLATES_DIR, templatePath);
  const fileName = path.basename(templatePath, '.mdx');
  const dirPath = path.dirname(relativePath);

  // Category files can be either index or README
  if (fileName === 'index' || fileName === 'README') {
    return path.join(FRAGMENTS_DIR, dirPath, `${language}.incl.md`);
  } else {
    return path.join(FRAGMENTS_DIR, dirPath, fileName, `${language}.incl.md`);
  }
}

/**
 * Given an include file path, return the expected template path.
 */
function getTemplatePathFromInclude(includePath: string): string {
  const rel = path.relative(FRAGMENTS_DIR, includePath);
  const parts = rel.split(path.sep);

  // foo/bar/lang.incl.md => foo/bar.mdx
  if (parts.length >= 2) {
    return path.join(TEMPLATES_DIR, ...parts.slice(0, -1)) + '.mdx';
  } else {
    return '(unknown)';
  }
}

/**
 * Process LanguageInclude tags in template content and replace with Language components or raw content
 * - Production mode + target language: generates clean files with only raw content for that language
 * - Development mode: generates Language components with helpful error messages for missing content
 */
function processLanguageIncludeTags(
  templateContent: string,
  templatePath: string,
  targetLanguage?: Language
): string {
  let processedContent = templateContent;
  let hasLanguageInclude = false;

  // Replace all LanguageInclude tags
  processedContent = processedContent.replace(
    LANGUAGE_INCLUDE_REGEX,
    (match, sectionName, inlineContent, offset) => {
      hasLanguageInclude = true;

      // Determine if this is inline or block based on context
      const beforeMatch = templateContent.substring(0, offset);

      // Check if the tag is at the start of a line or after only whitespace (block)
      // vs. if it's within text content (inline)
      const lineStart = beforeMatch.lastIndexOf('\n');
      const textBeforeOnLine = beforeMatch.substring(lineStart + 1);
      const isBlock = /^\s*$/.test(textBeforeOnLine);

      // Handle inline content (content={{...}})
      if (inlineContent) {
        try {
          // Parse the inline content object
          const contentObj = JSON.parse(inlineContent);
          
          // Production mode with target language
          if (isProduction && targetLanguage) {
            const content = contentObj[targetLanguage];
            return content || '';
          }
          
          // Development mode: generate Language components for all languages
          const languageComponents: string[] = [];
          for (const lang of LANGUAGES) {
            const content = contentObj[lang];
            if (content) {
              if (isBlock) {
                languageComponents.push(
                  `<Language language="${lang}">\n\n${content}\n\n</Language>`
                );
              } else {
                languageComponents.push(`<Language language="${lang}">${content}</Language>`);
              }
            }
          }
          return languageComponents.join('\n');
        } catch (error) {
          console.warn(`generate-language-docs warning: Error parsing inline content: ${error}`);
          return match; // Return original tag on error
        }
      }

      // Handle section reference (section="...")
      // Production mode with target language: only generate for that language
      if (isProduction && targetLanguage) {
        const inclPath = getIncludeFilePath(templatePath, targetLanguage);
        if (!fs.existsSync(inclPath)) {
          // Skip missing content (prod)
          return '';
        }

        try {
          const fileContent = readFileUtf8Normalized(inclPath);
          const sectionContent = extractSection(fileContent, sectionName);

          if (sectionContent === null || sectionContent === '' || sectionContent === 'EMPTY_SECTION') {
            // Skip missing sections (null), intentional N/A content (empty string), or empty sections
            return '';
          }

          return isBlock ? `${sectionContent}` : sectionContent;
        } catch (error) {
          console.warn(`generate-language-docs warning: Error reading ${inclPath}: ${error}`);
          return '';
        }
      }

      // Development mode or no target language: generate Language components for all languages
      // This allows dev-time rendering of messages indicating what include sections are missing.
      const languageComponents: string[] = [];
      const languagesToProcess = targetLanguage ? [targetLanguage] : LANGUAGES;

      for (const lang of languagesToProcess) {
        const inclPath = getIncludeFilePath(templatePath, lang);
        let sectionContent: string | null = null;

        const isLanguageRestricted = shouldGenerateForLanguage(templateContent, lang);

        if (!isLanguageRestricted) {
          // Template doesn't target this language; skip
          continue;
        }

        // Only mark as incl file path as used if this template is supposed to generate for this language
        processedIncludeFiles.add(path.resolve(inclPath));

        if (!fs.existsSync(inclPath)) {
          // File missing for a language the template should support - show error in development
          if (!isProduction) {
            const errorMsg = `[DevMode] Documentation file for ${LANGUAGE_NAMES[lang]} not found: ${path.relative(process.cwd(), inclPath)}`;
            if (isBlock) {
              languageComponents.push(
                `<Language language="${lang}">\n\n${errorMsg}\n\n</Language>`
              );
            } else {
              languageComponents.push(`<Language language="${lang}">${errorMsg}</Language>`);
            }
          }
          continue;
        }

        try {
          const fileContent = readFileUtf8Normalized(inclPath);
          sectionContent = extractSection(fileContent, sectionName);

          if (sectionContent === null || sectionContent === 'EMPTY_SECTION') {
            // Section not found (null) or section exists but has no content (EMPTY_SECTION)
            // Track this gap in the manifest
            const gapKey = normalizePath(path.relative(TEMPLATES_DIR, templatePath));
            if (!contentGapsManifest[gapKey]) {
              contentGapsManifest[gapKey] = {};
            }
            if (!contentGapsManifest[gapKey][sectionName]) {
              contentGapsManifest[gapKey][sectionName] = [];
            }
            contentGapsManifest[gapKey][sectionName].push(lang);

            // Both cases show the same error in development, skip in production
            if (!isProduction) {
              const errorMsg = `**[Dev] Section "${sectionName}" not found in ${LANGUAGE_NAMES[lang]} documentation.** Either mark the section explicitly as N/A for intentionally ignored, or fill in documentation.`;
              if (isBlock) {
                languageComponents.push(
                  `<Language language="${lang}">\n\n${errorMsg}\n\n</Language>`
                );
              } else {
                languageComponents.push(`<Language language="${lang}">${errorMsg}</Language>`);
              }
            }
            continue;
          }

          if (sectionContent === '') {
            // N/A section - intentionally skip any rendering
            continue;
          }

          // Valid content found
          if (isBlock) {
            // Block-level: full Language component with markdown processing
            languageComponents.push(
              `<Language language="${lang}">\n\n${sectionContent}\n\n</Language>`
            );
          } else {
            // Inline: single Language component with just the text content
            languageComponents.push(`<Language language="${lang}">${sectionContent}</Language>`);
          }
        } catch (error) {
          console.warn(`    Warning: Error reading ${inclPath}: ${error}`);
          // Generate error component in development
          if (!isProduction) {
            const errorMsg = `[Dev] Error reading file: ${error}`;
            if (isBlock) {
              languageComponents.push(
                `<Language language="${lang}">\n\n${errorMsg}\n\n</Language>`
              );
            } else {
              languageComponents.push(`<Language language="${lang}">${errorMsg}</Language>`);
            }
          }
        }
      }

      // Return joined Language components (or empty string if no components added)
      if (isBlock) {
        // Block: Each language on separate lines
        return languageComponents.join('\n\n');
      } else {
        // Inline: Return all language components without line breaks to preserve list structure
        return languageComponents.join('');
      }
    }
  );

  // Add Language component import if we processed any LanguageInclude tags and need Language components
  const needsLanguageImport =
    hasLanguageInclude &&
    (!isProduction || !targetLanguage) &&
    !processedContent.includes("import Language from '@site/src/components/Language'");

  if (needsLanguageImport) {
    // Find where to insert the import (after frontmatter if it exists)
    const frontmatterMatch = processedContent.match(FRONTMATTER_REGEX);
    const insertPosition = frontmatterMatch ? frontmatterMatch[0].length : 0;

    const importStatement = "import Language from '@site/src/components/Language';\n\n";
    processedContent =
      processedContent.slice(0, insertPosition) +
      importStatement +
      processedContent.slice(insertPosition);
  }

  return processedContent;
}

function deleteInDirectory(dir: string, deletedCount: { count: number }): void {
  const entries = fs.readdirSync(dir, { withFileTypes: true });

  for (const entry of entries) {
    const fullPath = path.join(dir, entry.name);

    if (entry.isDirectory()) {
      deleteInDirectory(fullPath, deletedCount);
      // Remove empty directories
      try {
        fs.rmdirSync(fullPath);
      } catch (e) {
        // Directory not empty and will be cleaned up later
      }
    } else if (entry.isFile() && entry.name.endsWith('.mdx')) {
      fs.unlinkSync(fullPath);
      deletedCount.count++;
    } else if (entry.isFile() && entry.name === '_category_.json') {
      // Delete all category files - they will be regenerated from templates
      fs.unlinkSync(fullPath);
      deletedCount.count++;
    }
  }
}

/**
 * Clean up stale generated files before regeneration
 * Removes all .mdx files from docs/main/{lang}/ directories
 */
function cleanGeneratedFiles(): void {
  console.log('Cleaning up stale generated files...');

  let deletedCount = { count: 0 };

  for (const lang of LANGUAGES) {
    const langDir = path.join(DOCS_BASE, lang);

    if (!fs.existsSync(langDir)) {
      continue;
    }

    // Also remove root-level category file for this language
    const rootCategoryPath = path.join(langDir, '_category_.json');

    if (fs.existsSync(rootCategoryPath)) {
      fs.unlinkSync(rootCategoryPath);
      deletedCount.count++;
    }

    // Recursively find and delete all .mdx and _category_.json files
    deleteInDirectory(langDir, deletedCount);
  }

  if (deletedCount.count === 0) {
    console.log('No files to clean');
  } else {
    console.log(`  Cleaned up ${deletedCount.count} file(s)\n`);
  }
}

/**
 * Clean up generated files for a specific template
 * Removes the generated .mdx files for all languages
 */
function cleanGeneratedFilesForTemplate(templatePath: string): void {
  const relativePath = path.relative(TEMPLATES_DIR, templatePath);
  const templateName = path.basename(templatePath);

  for (const lang of LANGUAGES) {
    const outputDir = path.join(DOCS_BASE, lang, path.dirname(relativePath));
    // Handle both README.mdx -> index.mdx conversion and regular files
    // Note: README.mdx category templates are converted to index.mdx for generated output
    const outputFileName = templateName === 'README.mdx' ? 'index.mdx' : templateName;
    const outputPath = path.join(outputDir, outputFileName);

    if (fs.existsSync(outputPath)) {
      fs.unlinkSync(outputPath);
      console.log(`  Removed: docs/main/${lang}/${path.dirname(relativePath)}/${outputFileName}`);
    }
  }
}

/**
 * Check if a template should be generated for a specific language based on frontmatter
 */
function shouldGenerateForLanguage(templateContent: string, language: Language): boolean {
  const { frontmatter } = FrontmatterParser.extract(templateContent);

  // Check if languages array is specified
  if (frontmatter.languages && Array.isArray(frontmatter.languages)) {
    return frontmatter.languages.includes(language);
  }

  // No language restriction = generate for all languages
  return true;
}

/**
 * Generate language-specific doc files from templates
 * Templates in src/components/ (with nested dirs) are copied to docs/main/{lang}/
 * Preserves directory structure and processes LanguageInclude tags
 */
function generateDocsForTemplate(templatePath: string): void {
  // Calculate relative path from TEMPLATES_DIR to preserve nested structure
  const relativePath = normalizePath(path.relative(TEMPLATES_DIR, templatePath));
  const templateName = path.basename(templatePath);

  // Read template content (normalize CRLF > LF)
  const templateContent = readFileUtf8Normalized(templatePath);

  // Check frontmatter for warning suppression
  const { frontmatter } = FrontmatterParser.extract(templateContent);
  const suppressLanguageIncludeWarning = frontmatter.suppressLanguageIncludeWarning === true;

  // Validate template contained LanguageInclude tags (unless suppressed)
  if (!suppressLanguageIncludeWarning && !templateContent.includes('<LanguageInclude')) {
    console.warn(
      `\nWarning: Template "${relativePath}" does not contain <LanguageInclude /> tags.`
    );
    console.warn(
      `  If the file is intended to be identical for all languages, ignore this warning.\n  Suppress this warning by adding suppressLanguageIncludeWarning: true to the file's fronmatter`
    );
  }

  // Track which languages this page is missing from
  const pagePath =
    relativePath
      .replace(/\.mdx?$/, '')
      .replace(/README$/, '')
      .replace(/\/$/, '') || '/';
  const missingLanguages: Language[] = [];

  for (const lang of LANGUAGES) {
    // Check if this template should be generated for this language
    if (!shouldGenerateForLanguage(templateContent, lang)) {
      missingLanguages.push(lang);
      continue;
    }

    const processedContent = processLanguageIncludeTags(templateContent, templatePath, lang);

    // Extract frontmatter if exists
    const { frontmatter, hasFrontmatter, content: contentWithoutFrontmatter } = FrontmatterParser.extract(processedContent);
    let content = contentWithoutFrontmatter;
    let frontmatterRaw = '';

    if (hasFrontmatter && frontmatter && Object.keys(frontmatter).length > 0) {
      frontmatterRaw = `---\n${yaml.dump(frontmatter)}---\n`
    }

    const outputDir = path.join(DOCS_BASE, lang, path.dirname(relativePath));
    // Convert README.mdx to index.mdx so it becomes the category page content
    const outputFileName = templateName === 'README.mdx' ? 'index.mdx' : templateName;
    const outputPath = path.join(outputDir, outputFileName);

    // Ensure directory exists
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }

    // Build output content
    let output = '';

    // Add frontmatter first if it exists (must be at the very top)
    if (frontmatter) {
      output += `${frontmatterRaw}\n`;
    }

    // Add auto-generation warning after frontmatter
    output += `<!--\n`;
    output += `  AUTO-GENERATED FILE - DO NOT EDIT\n`;
    output += `  This file is generated from: src/pages/templates/${relativePath}\n`;
    output += `  To make changes, edit the template file, then run: npm run generate:docs\n`;
    output += `-->\n\n`;

    // Add processed content (optimized for production, with Language components for development)
    output += content;

    // Write file
    fs.writeFileSync(outputPath, output, 'utf8');
  }

  // Only add to manifest if some languages are missing
  if (missingLanguages.length > 0) {
    missingPagesManifest[pagePath] = missingLanguages;
  }
}

/**
 * Copy category configuration files to all language directories
 * Copies _category_.json files from template directories to docs/main/{lang}/
 * Preserves directory structure
 */
function copyCategoryFiles(): void {
  function copyDirectory(sourceDir: string, relativePath: string = ''): void {
    const entries = fs.readdirSync(sourceDir, { withFileTypes: true });

    for (const entry of entries) {
      const sourcePath = path.join(sourceDir, entry.name);
      const currentRelativePath = path.join(relativePath, entry.name);

      if (entry.isDirectory()) {
        copyDirectory(sourcePath, currentRelativePath);
      } else if (entry.isFile() && entry.name === '_category_.json') {
        // Copy category file to all language directories with unique keys
        const categoryContent = JSON.parse(readFileUtf8Normalized(sourcePath));

        for (const lang of LANGUAGES) {
          const targetDir = path.join(DOCS_BASE, lang, relativePath);
          const targetPath = path.join(targetDir, '_category_.json');

          // Ensure target directory exists
          if (!fs.existsSync(targetDir)) {
            fs.mkdirSync(targetDir, { recursive: true });
          }

          // Add unique key based on language and relative path
          const modifiedContent = {
            ...categoryContent,
            key: `${lang}-${relativePath.replace(/[/\\]/g, '-') || 'root'}`,
          };

          fs.writeFileSync(targetPath, JSON.stringify(modifiedContent, null, 2) + '\n');
        }
      }
    }
  }

  copyDirectory(TEMPLATES_DIR);
}

/**
 * Find all template files in src/components recursively
 */
function findTemplateFiles(): string[] {
  if (!fs.existsSync(TEMPLATES_DIR)) {
    console.error(`Templates directory not found: ${TEMPLATES_DIR}`);
    return [];
  }

  const templates: string[] = [];

  function searchDirectory(dir: string): void {
    const entries = fs.readdirSync(dir, { withFileTypes: true });

    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);

      if (entry.isDirectory()) {
        searchDirectory(fullPath);
      } else if (entry.isFile() && entry.name.endsWith('.mdx')) {
        // Skip generation of underscore-prefixed files (utility/unlisted templates)
        if (entry.name.startsWith('_')) {
          continue;
        }
        templates.push(fullPath);
      }
    }
  }

  searchDirectory(TEMPLATES_DIR);
  // Deterministic ordering across platforms
  templates.sort((a, b) => normalizePath(a).localeCompare(normalizePath(b)));
  return templates;
}

/**
 * Create root-level category files for each language directory
 * Creates _category_.json files in docs/main/{lang}/ with proper positioning
 */
function createLanguageRootCategories(): void {
  // Position values for each language for correct sidebar ordering
  const languagePositions = {
    typescript: 2.0,
    csharp: 2.1,
    python: 2.2,
  };

  for (const lang of LANGUAGES) {
    const langDir = path.join(DOCS_BASE, lang);
    const categoryPath = path.join(langDir, '_category_.json');

    // Ensure directory exists
    if (!fs.existsSync(langDir)) {
      fs.mkdirSync(langDir, { recursive: true });
    }

    // Create category configuration
    const categoryConfig = {
      label: `${LANGUAGE_NAMES[lang]} Guide`,
      position: languagePositions[lang],
      collapsible: true,
      collapsed: false,
    };

    // Write the category file
    fs.writeFileSync(categoryPath, JSON.stringify(categoryConfig, null, 2), 'utf8');
  }
}

// After all templates are processed, warn about orphaned include files
function warnOrphanedIncludeFiles() {
  const orphanedFiles: Array<{ lang: string; fullPath: string; relTemplate: string }> = [];
  function scanDir(dir: string) {
    const entries = fs.readdirSync(dir, { withFileTypes: true });
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        scanDir(fullPath);
      } else if (entry.isFile() && entry.name.endsWith('.incl.md')) {
        if (!processedIncludeFiles.has(path.resolve(fullPath))) {
          // Extract language from filename
          const match = entry.name.match(LANGUAGE_INCL_FILENAME_REGEX);
          const lang = match ? match[1] : 'unknown';
          const templatePath = getTemplatePathFromInclude(fullPath);
          const relTemplate = normalizePath(path.relative(process.cwd(), templatePath));
          orphanedFiles.push({ lang, fullPath, relTemplate });
        }
      }
    }
  }
  scanDir(FRAGMENTS_DIR);
  if (orphanedFiles.length > 0) {
    console.warn(`\n[DevMode] Orphaned include files were found. These files are not referenced by any template (possibly due to 'language' frontmatter restrictions):`);
    orphanedFiles.forEach(({ lang, fullPath, relTemplate }) => {
      console.warn(`  - [${lang}] ${fullPath}\n      Template: ${relTemplate}`);
    });
  }
}

/**
 * Write the missing pages manifest to static directory
 */
function writePageManifest(): void {
  const manifestPath = normalizePath(path.join(__dirname, '..', 'static', 'missing-pages.json'));

  // Ensure static directory exists
  const staticDir = path.dirname(manifestPath);
  if (!fs.existsSync(staticDir)) {
    fs.mkdirSync(staticDir, { recursive: true });
  }

  // Write compact JSON with only pages that are missing from some languages
  // Ensure deterministic sorting across platforms using json-stable-stringify
  fs.writeFileSync(manifestPath, stringify(missingPagesManifest, { space: 2 }) + '\n', 'utf8');
  console.log(
    `\nWrote missing pages manifest to ${path.relative(process.cwd(), manifestPath)} (${Object.keys(missingPagesManifest).length} entries)`
  );
}

/**
 * Write the content gaps manifest for tracking missing sections
 */
function writeContentGapsManifest(): void {
  const generatedDir = normalizePath(path.join(__dirname, 'generated'));
  const manifestPath = normalizePath(path.join(generatedDir, 'content-gaps.json'));
  const readmePath = normalizePath(path.join(generatedDir, 'content-gaps.md'));

  // Ensure generated directory exists
  if (!fs.existsSync(generatedDir)) {
    fs.mkdirSync(generatedDir, { recursive: true });
  }

  // Directly stringify manifest (order not important; stable stringify ensures deterministic output anyway)
  fs.writeFileSync(manifestPath, stringify(contentGapsManifest, { space: 2 }) + '\n', 'utf8');

  // Generate human-readable markdown report
  let markdownContent = `# Content Gaps Report\n\n`;
  markdownContent += `Generated: ${new Date().toISOString()}\n\n`;
  markdownContent += `This report tracks missing sections in language-specific documentation.\n\n`;

  const totalGaps = Object.keys(contentGapsManifest).length;

  markdownContent += `**${totalGaps} template(s) have missing sections**\n\n`;

  if (totalGaps > 0) {
    for (const [templatePath, sections] of Object.entries(contentGapsManifest)) {
      markdownContent += `## \`${templatePath}\`\n\n`;
      for (const [sectionName, languages] of Object.entries(sections)) {
        const langNames = languages.map(lang => LANGUAGE_NAMES[lang]).join(', ');
        markdownContent += `- **\`${sectionName}\`**: Missing in ${langNames}\n`;
      }
      markdownContent += `\n`;
    }
  }

  markdownContent += `## Summary\n\n`;
  const totalSectionGaps = Object.values(contentGapsManifest)
    .flatMap(sections => Object.values(sections))
    .reduce((total, langs: Language[]) => total + langs.length, 0);
  markdownContent += `- **${totalGaps}** templates with gaps\n`;
  markdownContent += `- **${totalSectionGaps}** total missing sections\n`;

  fs.writeFileSync(readmePath, markdownContent, 'utf8');

  console.log(
    `\nWrote content gaps manifest to ${path.relative(process.cwd(), manifestPath)} (${totalGaps} templates with gaps)`
  );
  console.log(`Generated readable report: ${path.relative(process.cwd(), readmePath)}`);
}

interface GenerationResult {
  templatesGenerated: number;
  contentGapsFound: number;
}

/**
 * Generate all docs
 * @returns Generation result with template count and content gaps found
 */
function generateAll(): GenerationResult {
  console.log('generate-language-docs.ts: Generating language-specific documentation...\n');

  // Clean up stale files first
  cleanGeneratedFiles();

  // Reset manifests
  Object.keys(missingPagesManifest).forEach((key) => delete missingPagesManifest[key]);
  Object.keys(contentGapsManifest).forEach((key) => delete contentGapsManifest[key]);

  const templates = findTemplateFiles();

  if (templates.length === 0) {
    console.log('No template files found in src/pages/templates/');
    return { templatesGenerated: 0, contentGapsFound: 0 };
  }

  templates.forEach(generateDocsForTemplate);

  // Copy category configuration files
  copyCategoryFiles();

  // Create root-level category files for language directories
  createLanguageRootCategories();

  // Warn about orphaned include files
  if (!isProduction) {
    warnOrphanedIncludeFiles();
  }

  // Write the page manifest
  writePageManifest();

  // Write the content gaps manifest
  writeContentGapsManifest();

  console.log(`\nGenerated ${templates.length} template(s) for ${LANGUAGES.length} languages\n`);

  return {
    templatesGenerated: templates.length,
    contentGapsFound: Object.keys(contentGapsManifest).length,
  };
}

/**
 * Watch mode for development
 */
function watch(): void {
  console.log('\nWatching for template and fragment changes...\n');

  // Watch templates
  const templateWatcher = chokidar.watch(path.join(TEMPLATES_DIR, '**/*.mdx'), {
    persistent: true,
    ignoreInitial: true,
  });

  templateWatcher.on('add', (filePath: string) => {
    generateDocsForTemplate(filePath);
  });

  templateWatcher.on('change', (filePath: string) => {
    generateDocsForTemplate(filePath);
  });

  templateWatcher.on('unlink', (filePath: string) => {
    cleanGeneratedFilesForTemplate(filePath);
  });

  // Watch Language Include/fragment files (*.incl.md)
  const inclWatcher = chokidar.watch(path.join(FRAGMENTS_DIR, '**/*.incl.md'), {
    persistent: true,
    ignoreInitial: true,
  });

  /**
   * Handle changes to include files and regenerate corresponding templates
   * Maps include file paths to their corresponding template files:
   * - Category pages: src/components/include/{path}/{lang}.incl.md → src/pages/templates/{path}/README.mdx
   * - Regular pages: src/components/include/{path}/{page}/{lang}.incl.md → src/pages/templates/{path}/{page}.mdx
   */
  const handleInclChange = (filePath: string): void => {
    const relativePath = path.relative(FRAGMENTS_DIR, filePath);
    const parts = relativePath.split(path.sep);

    const langFile = parts.pop();

    let templatePath: string;

    if (langFile && LANGUAGE_INCL_FILENAME_REGEX.test(langFile)) {
      templatePath = path.join(TEMPLATES_DIR, ...parts, 'README.mdx');

      if (!fs.existsSync(templatePath)) {
        templatePath = path.join(TEMPLATES_DIR, ...parts) + '.mdx';
      }
    } else {
      templatePath = path.join(TEMPLATES_DIR, ...parts) + '.mdx';
    }

    if (fs.existsSync(templatePath)) {
      console.log(`\nFragment changed: ${relativePath}`);
      console.log(`Regenerating template: ${path.relative(TEMPLATES_DIR, templatePath)}`);
      generateDocsForTemplate(templatePath);
    } else {
      console.warn(`\nFragment changed but template not found: ${templatePath}`);
      console.warn('This might be an orphaned fragment file.');
    }
  };

  inclWatcher.on('change', handleInclChange);
  inclWatcher.on('add', handleInclChange);

  // Watch category configuration files in templates
  const categoryWatcher = chokidar.watch(path.join(TEMPLATES_DIR, '**/_category_.json'), {
    persistent: true,
    ignoreInitial: true,
  });

  categoryWatcher.on('change', () => {
    copyCategoryFiles();
  });

  categoryWatcher.on('add', () => {
    copyCategoryFiles();
  });
}

// Main execution
if (require.main === module) {
  const args = process.argv.slice(2);
  const watchMode = args.includes('--watch') || args.includes('-w');

  if (watchMode) {
    generateAll();
    watch();
  } else {
    const result = generateAll();

    // In production mode, fail the build if there are content gaps
    if (isProduction && result.contentGapsFound > 0) {
      console.error(`\n❌ Build failed: Found ${result.contentGapsFound} template(s) with content gaps in production mode.`);
      console.error('Please fill in all missing sections or mark them as N/A before deploying.\n');
      process.exit(1);
    }
  }
}

export { generateAll, generateDocsForTemplate };


================================================
FILE: teams.md/scripts/generate-llms-txt.ts
================================================
#!/usr/bin/env node

import * as fs from 'fs';
import * as path from 'path';

import { collectFiles, getHierarchicalFiles } from './lib/file-collector';
import { processContent } from './lib/content-processor';
import { FrontmatterParser } from './lib/frontmatter-parser';
import { LANGUAGES, Language, LANGUAGE_NAMES } from '../src/constants/languages';
import readFileUtf8Normalized from '../src/utils/readFileUtf8Normalized';

const LANGUAGE_SPECIFIC_TIPS: Record<Language, string[]> = {
    typescript: [
        "It's a good idea to build the application using `npm run build` and fix compile time errors to help ensure the app works as expected.",
        "The SDK uses typescript to help you make the right decisions when using the APIs. You may check type definitions and type checkers to make sure your code is correct."
    ],
    python: [
        "It's a good idea to run `pyright` to make sure the code is correctly typed and fix any type errors.",
    ],
    csharp: [
        "It's a good idea to build the application and fix compile time errors to help ensure the app works as expected.",
        "It is helpful to inspect NuGet packages folder to get exact types for a given namesapce"
    ]
};

const COMMON_OVERALL_SUMMARY = (language: Language) => {
    const langName = LANGUAGE_NAMES[language];
    const tips = LANGUAGE_SPECIFIC_TIPS[language];
    const formattedTips = tips.map(tip => `- ${tip}`).join('\n');

    return `> Microsoft Teams SDK - A comprehensive framework for building AI-powered Teams applications using ${langName}. Using this SDK, you can easily build and integrate a variety of features in Microsoft Teams by building Agents or Tools. The documentation here helps by giving background information and code samples on how best to do this.

IMPORTANT THINGS TO REMEMBER:
- This SDK is NOT based off of BotFramework (which the _previous_ version of the Teams SDK was based on). This SDK is a completely new framework. Use this guide to find snippets to drive your decisions.
- When scaffolding new applications, using the CLI is a lot simpler and preferred than doing it all by yourself. See the Quickstart guide for that.
${formattedTips}

YOU MUST FOLLOW THE ABOVE GUIDANCE.`;
};

interface DocusaurusConfig {
    url: string;
    baseUrl: string;
}

interface ProcessedFile {
    title: string;
    content: string;
    frontmatter: { [key: string]: any };
    filePath: string;
    sidebarPosition: number;
    relativeUrl: string;
}

interface FileInfo {
    name: string;
    title: string;
    path: string;
    order: number;
}

interface FolderStructure {
    title: string;
    order: number;
    path: string;
    files: FileInfo[];
    children: { [key: string]: FolderStructure };
}

/**
 * Reads Docusaurus config to get base URL
 * @param baseDir - Base directory path
 * @returns Config object with url and baseUrl
 */
function getDocusaurusConfig(baseDir: string): DocusaurusConfig {
    try {
    // Read the docusaurus.config.ts file
    const configPath = path.join(baseDir, 'docusaurus.config.ts');
    const configContent = readFileUtf8Normalized(configPath);

        // Extract URL and baseUrl using regex (simple approach)
        const urlMatch = configContent.match(/url:\s*['"]([^'"]+)['"]/);
        const baseUrlMatch =
            configContent.match(/baseUrl\s*=\s*['"]([^'"]+)['"]/) ||
            configContent.match(/baseUrl:\s*['"]([^'"]+)['"]/);

        const url = urlMatch ? urlMatch[1] : 'https://microsoft.github.io';
        const baseUrl = baseUrlMatch ? baseUrlMatch[1] : '/teams-sdk/';

        return { url, baseUrl };
    } catch (error) {
        console.warn('⚠️ Could not read Docusaurus config, using defaults');
        return { url: 'https://microsoft.github.io', baseUrl: '/teams-sdk/' };
    }
}

/**
 * Generates llms.txt files for Teams SDK documentation
 * Creates both small and full versions for TypeScript and C# docs
 */
async function generateLlmsTxt(): Promise<void> {
    console.log('🚀 Starting llms.txt generation...');

    const baseDir = path.join(__dirname, '..');
    const outputDir = path.join(baseDir, 'static', 'llms_docs');

    // Get Docusaurus configuration
    const config = getDocusaurusConfig(baseDir);
    const cleanUrl = config.url.replace(/\/$/, '');
    const cleanBaseUrl = config.baseUrl.startsWith('/') ? config.baseUrl : '/' + config.baseUrl;
    console.log(`📍 Using base URL: ${cleanUrl}${cleanBaseUrl}`);

    // Ensure output directory exists
    if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true });
    }

    try {
        // Generate llms.txt files for all languages
        for (const language of LANGUAGES) {
            const langName = LANGUAGE_NAMES[language];
            console.log(`📝 Generating ${langName} llms.txt files...`);
            await generateLanguageFiles(language, baseDir, outputDir, config);
        }

        console.log('✅ Successfully generated all llms.txt files!');
    } catch (error) {
        console.error('❌ Error generating llms.txt files:', error);
        process.exit(1);
    }
}

/**
 * Generates llms.txt files for a specific language
 * @param language - 'typescript', 'python', or 'csharp'
 * @param baseDir - Base directory path
 * @param outputDir - Output directory path
 * @param config - Docusaurus config object
 */
async function generateLanguageFiles(language: Language, baseDir: string, outputDir: string, config: DocusaurusConfig): Promise<void> {
    // Collect all relevant files
    const mainFiles: string[] = [];
    const langFiles = collectFiles(path.join(baseDir, 'docs', 'main', language));

    // Process all files to get metadata and file mapping
    const { processedFiles, fileMapping } = await processAllFiles(
        [...mainFiles, ...langFiles],
        baseDir,
        language
    );

    // Generate individual TXT files for each doc
    await generateIndividualTxtFiles(
        processedFiles,
        outputDir,
        language,
        baseDir,
        config,
        fileMapping
    );

    // Process content for small version (navigation index)
    const smallContent = await generateSmallVersionHierarchical(
        language,
        baseDir,
        config,
        fileMapping
    );

    // Process content for full version (all documentation)
    const fullContent = await generateFullVersion(language, processedFiles, baseDir);

    // Write main llms.txt files
    const smallPath = path.join(outputDir, `llms_${language}.txt`);
    const fullPath = path.join(outputDir, `llms_${language}_full.txt`);

    fs.writeFileSync(smallPath, smallContent, 'utf8');
    fs.writeFileSync(fullPath, fullContent, 'utf8');

    console.log(`  ✓ Generated ${path.basename(smallPath)} (${formatBytes(smallContent.length)})`);
    console.log(`  ✓ Generated ${path.basename(fullPath)} (${formatBytes(fullContent.length)})`);
    console.log(`  ✓ Generated ${processedFiles.length} individual .txt files`);
}

/**
 * Processes all files and returns structured data
 * @param allFiles - All file paths to process
 * @param baseDir - Base directory path
 * @param language - Language identifier for filtering language-specific files
 * @returns Object with processedFiles array and fileMapping Map
 */
async function processAllFiles(allFiles: string[], baseDir: string, language: Language): Promise<{ processedFiles: ProcessedFile[]; fileMapping: Map<string, string> }> {
    const processedFiles: ProcessedFile[] = [];

    // First pass: build file mapping
    const fileMapping = new Map<string, string>();
    for (const file of allFiles) {
        // Generate the same filename logic as used in generateIndividualTxtFiles
        const tempProcessed = await processContent(file, baseDir, false, null, null, language); // Quick pass for title with language filtering
        if (tempProcessed) {
            // Only process files that aren't marked to ignore
            let fileName: string;
            if (path.basename(file) === 'README.md') {
                const parentDir = path.basename(path.dirname(file));
                fileName = generateSafeFileName(parentDir);
            } else {
                fileName = generateSafeFileName(tempProcessed.title || file);
            }
            fileMapping.set(file, fileName);
        }
    }

    // Second pass: process files with mapping for link resolution
    for (const file of allFiles) {
        const processed = await processContent(file, baseDir, true, fileMapping, null, language);
        if (processed && (processed.title || processed.content)) {
            processedFiles.push(processed);
        }
    }

    // Sort by sidebar position, then by title
    const sortedFiles = processedFiles.sort((a, b) => {
        const posA = a.sidebarPosition || 999;
        const posB = b.sidebarPosition || 999;

        if (posA !== posB) {
            return posA - posB;
        }

        return (a.title || '').localeCompare(b.title || '');
    });

    return { processedFiles: sortedFiles, fileMapping };
}

/**
 * Generates individual .txt files for each documentation file
 * @param processedFiles - Array of processed file objects
 * @param outputDir - Output directory path
 * @param language - Language identifier
 * @param baseDir - Base directory path
 * @param config - Docusaurus config object
 * @param fileMapping - File mapping for link resolution
 */
async function generateIndividualTxtFiles(
    processedFiles: ProcessedFile[],
    outputDir: string,
    language: Language,
    baseDir: string,
    config: DocusaurusConfig,
    fileMapping: Map<string, string>
): Promise<void> {
    const docsDir = path.join(outputDir, `docs_${language}`);

    // Clean and recreate docs directory to remove old files
    if (fs.existsSync(docsDir)) {
        fs.rmSync(docsDir, { recursive: true });
    }
    fs.mkdirSync(docsDir, { recursive: true });

    for (const file of processedFiles) {
        if (!file.content) continue;

        // Re-process the file with full URL generation for individual files
        const reprocessed = await processContent(
            file.filePath,
            baseDir,
            true,
            fileMapping,
            config,
            language
        );

        if (!reprocessed) continue;

        // Generate safe filename - use folder name for README.md files
        let fileName: string;
        if (path.basename(file.filePath) === 'README.md') {
            // Use parent folder name for README files
            const parentDir = path.basename(path.dirname(file.filePath));
            fileName = generateSafeFileName(parentDir);
        } else {
            fileName = generateSafeFileName(file.title || file.filePath);
        }

        const outputPath = path.join(docsDir, `${fileName}.txt`);

        // Use the reprocessed content directly without adding metadata header
        let txtContent = reprocessed.content || file.content; // Use reprocessed content with full URLs

        fs.writeFileSync(outputPath, txtContent, 'utf8');
    }
}

/**
 * Generates the small version of llms.txt (navigation index)
 * @param language - Language identifier
 * @param baseDir - Base directory path
 * @param config - Docusaurus config object
 * @param fileMapping - Mapping of source files to generated filenames
 * @returns Generated navigation content
 */
async function generateSmallVersionHierarchical(language: Language, baseDir: string, config: DocusaurusConfig, fileMapping: Map<string, string>): Promise<string> {
    const langName = LANGUAGE_NAMES[language];
    // Remove trailing slash from URL and ensure baseUrl starts with slash
    const cleanUrl = config.url.replace(/\/$/, '');
    const cleanBaseUrl = config.baseUrl.startsWith('/') ? config.baseUrl : '/' + config.baseUrl;
    const fullBaseUrl = `${cleanUrl}${cleanBaseUrl}`;

    let content = `# Teams SDK - ${langName} Documentation\n\n`;
    content += COMMON_OVERALL_SUMMARY(language) + '\n\n';

    // Get hierarchical structure
    const hierarchical = getHierarchicalFiles(baseDir, `main/${language}`);

    // Add Language-specific Documentation
    content += renderHierarchicalStructure(hierarchical.language, fullBaseUrl, language, fileMapping, 0);

    return content;
}

/**
 * Renders hierarchical structure with proper indentation
 * @param structure - Hierarchical structure object
 * @param baseUrl - Base URL for links
 * @param language - Language identifier
 * @param fileMapping - Mapping of source files to generated filenames
 * @param indentLevel - Current indentation level (0 = section headers, 1+ = bullet points)
 * @returns Rendered content with proper hierarchy
 */
function renderHierarchicalStructure(structure: { [key: string]: FolderStructure }, baseUrl: string, language: Language, fileMapping: Map<string, string>, indentLevel: number = 0): string {
    let content = '';

    // Helper function for folder name formatting
    function formatFolderName(name: string): string {
        return name.replace(/[-_]/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
    }

    // Convert structure to sorted array
    const folders = Object.entries(structure)
        .map(([key, value]) => ({ key, ...value }))
        .sort((a, b) => {
            const orderA = a.order || 999;
            const orderB = b.order || 999;
            if (orderA !== orderB) return orderA - orderB;
            return a.key.localeCompare(b.key);
        });

    for (const folder of folders) {
        // Check if this folder has any content (files or children)
        const hasFiles = folder.files && folder.files.length > 0;
        const hasChildren = folder.children && Object.keys(folder.children).length > 0;
        const hasContent = hasFiles || hasChildren;

        if (hasContent) {
            // Check if this folder has a README file to make the header clickable
            const readmeFile = hasFiles
                ? folder.files.find((f) => path.basename(f.path) === 'README.md')
                : null;
            const displayTitle =
                folder.title && folder.title !== folder.key ? folder.title : formatFolderName(folder.key);

            // Generate indent for nested folders (use spaces, 2 per level)
            const indent = '  '.repeat(indentLevel);

            if (readmeFile) {
                // Make folder header clickable by linking to the README
                let folderFileName: string;
                if (fileMapping && fileMapping.has(readmeFile.path)) {
                    folderFileName = fileMapping.get(readmeFile.path)!;
                } else {
                    folderFileName = generateSafeFileName(folder.key);
                }

                // Use ### header for top-level sections (indentLevel 0), bullet points for nested
                if (indentLevel === 0) {
                    content += `### [${displayTitle}](${baseUrl}llms_docs/docs_${language}/${folderFileName}.txt)\n\n`;
                } else {
                    content += `${indent}- [${displayTitle}](${baseUrl}llms_docs/docs_${language}/${folderFileName}.txt)`;
                }

                // Add summary from README if available
                try {
                    const readmeContent = readFileUtf8Normalized(readmeFile.path);
                    const { frontmatter } = FrontmatterParser.extract(readmeContent);
                    const summary = frontmatter.summary;
                    if (summary) {
                        if (indentLevel === 0) {
                            content += `${summary}\n\n`;
                        } else {
                            content += `: ${summary}`;
                        }
                    }
                } catch (error) {
                    // Ignore errors reading README summary
                }

                if (indentLevel > 0) {
                    content += '\n';
                }
            } else {
                // No README
                if (indentLevel === 0) {
                    content += `### ${displayTitle}\n\n`;
                } else {
                    content += `${indent}- ${displayTitle}\n`;
                }
            }

            // Add files in this folder (sorted by order), excluding README
            if (hasFiles) {
                const sortedFiles = [...folder.files]
                    .filter((f) => path.basename(f.path) !== 'README.md') // Exclude README since it's now the header link
                    .sort((a, b) => {
                        const orderA = a.order || 999;
                        const orderB = b.order || 999;
                        if (orderA !== orderB) return orderA - orderB;
                        return a.name.localeCompare(b.name);
                    });

                for (const file of sortedFiles) {
                    // Use file mapping to get the correct generated filename
                    let fileName: string;
                    if (fileMapping && fileMapping.has(file.path)) {
                        fileName = fileMapping.get(file.path)!;
                    } else {
                        fileName = generateSafeFileName(file.title || file.name);
                    }

                    const summary = extractSummaryFromFile(file.path);

                    // Files are always indented one level deeper than their parent folder
                    const fileIndent = '  '.repeat(indentLevel + 1);
                    content += `${fileIndent}- [${file.title}](${baseUrl}llms_docs/docs_${language}/${fileName}.txt)`;
                    if (summary) {
                        content += `: ${summary}`;
                    }
                    content += '\n';
                }
            }

            // Recursively render children with increased indent
            if (hasChildren) {
                content += renderHierarchicalStructure(folder.children, baseUrl, language, fileMapping, indentLevel + 1);
            }

            // Add spacing after top-level sections
            if (indentLevel === 0) {
                content += '\n';
            }
        }
    }

    return content;
}

/**
 * Extracts summary from a file (cached approach)
 * @param filePath - Path to the file
 * @returns File summary or empty string
 */
function extractSummaryFromFile(filePath: string): string {
    try {
        const fileContent = readFileUtf8Normalized(filePath);

        // First check for summary in frontmatter
        const { frontmatter, content } = FrontmatterParser.extract(fileContent);
        const summary = frontmatter.summary;
        if (summary && typeof summary === 'string') {
            return summary;
        }

        // Remove HTML comments before extracting summary
        // Generated .mdx files contain AUTO-GENERATED warnings that shouldn't appear in summaries
        const cleanContent = content.replace(/<!--[\s\S]*?-->/g, '');

        // Fallback to extracting first meaningful paragraph if no summary in frontmatter
        const paragraphs = cleanContent.split('\n\n');
        for (const paragraph of paragraphs) {
            const clean = paragraph
                .replace(/#+\s*/g, '') // Remove headers
                .replace(/\*\*(.+?)\*\*/g, '$1') // Remove bold
                .replace(/\*(.+?)\*/g, '$1') // Remove italic
                .replace(/`(.+?)`/g, '$1') // Remove inline code
                .replace(/\[(.+?)\]\(.+?\)/g, '$1') // Remove links, keep text
                .trim();

            if (clean.length > 20 && !clean.startsWith('```') && !clean.startsWith('import')) {
                return clean.length > 100 ? clean.substring(0, 100) + '...' : clean;
            }
        }
    } catch (error) {
        // Ignore file read errors
    }

    return '';
}

/**
 * Generates the full version of llms.txt (complete documentation)
 * @param language - Language identifier
 * @param processedFiles - Array of processed file objects
 * @param baseDir - Base directory path
 * @returns Generated content
 */
async function generateFullVersion(language: Language, processedFiles: ProcessedFile[], baseDir: string): Promise<string> {
    const langName = LANGUAGE_NAMES[language]
    let content = `# Teams SDK - ${langName} Documentation (Complete)\n\n`;
    content += COMMON_OVERALL_SUMMARY(language) + '\n\n';

    // Group files by section
    const sections = groupFilesBySection(processedFiles, baseDir);

    // Process all sections
    for (const [sectionName, files] of Object.entries(sections)) {
        if (!files || files.length === 0) continue;

        content += `## ${formatSectionName(sectionName)}\n\n`;

        for (const file of files) {
            if (file.content) {
                content += `### ${file.title}\n\n${file.content}\n\n---\n\n`;
            }
        }
    }

    return content;
}

/**
 * Groups files by their section based on file path
 * @param processedFiles - Array of processed file objects
 * @param baseDir - Base directory path
 * @returns Grouped files by section
 */
function groupFilesBySection(processedFiles: ProcessedFile[], baseDir: string): { [key: string]: ProcessedFile[] } {
    const sections: { [key: string]: ProcessedFile[] } = {
        main: [],
        gettingStarted: [],
        essentials: [],
        inDepthGuides: [],
        migrations: [],
    };

    for (const file of processedFiles) {
        const relativePath = path.relative(path.join(baseDir, 'docs'), file.filePath);

        if (relativePath.startsWith('main/')) {
            sections.main.push(file);
        } else if (relativePath.includes('getting-started/')) {
            sections.gettingStarted.push(file);
        } else if (relativePath.includes('essentials/')) {
            sections.essentials.push(file);
        } else if (relativePath.includes('in-depth-guides/')) {
            sections.inDepthGuides.push(file);
        } else if (relativePath.includes('migrations/')) {
            sections.migrations.push(file);
        } else {
            // Create dynamic section based on directory
            const parts = relativePath.split('/');
            if (parts.length > 1) {
                const sectionKey = parts[1].replace(/[^a-zA-Z0-9]/g, '');
                if (!sections[sectionKey]) {
                    sections[sectionKey] = [];
                }
                sections[sectionKey].push(file);
            }
        }
    }

    // Sort files within each section by sidebar position
    for (const sectionFiles of Object.values(sections)) {
        sectionFiles.sort((a, b) => {
            const posA = a.sidebarPosition || 999;
            const posB = b.sidebarPosition || 999;

            if (posA !== posB) {
                return posA - posB;
            }

            return (a.title || '').localeCompare(b.title || '');
        });
    }

    return sections;
}

/**
 * Generates a safe filename from a title
 * @param title - Title to convert to filename
 * @returns Safe filename
 */
function generateSafeFileName(title: string): string {
    return (
        title
            .toLowerCase()
            .replace(/[^a-z0-9\s-]/g, '') // Remove special characters
            .replace(/\s+/g, '-') // Replace spaces with hyphens
            .replace(/-+/g, '-') // Replace multiple hyphens with single
            .replace(/^-|-$/g, '') // Remove leading/trailing hyphens
            .substring(0, 50) || // Limit length
        'untitled'
    );
}

/**
 * Formats a section name for display
 * @param sectionName - Section name to format
 * @returns Formatted section name
 */
function formatSectionName(sectionName: string): string {
    const nameMap: { [key: string]: string } = {
        main: 'Main Documentation',
        gettingStarted: 'Getting Started',
        essentials: 'Essentials',
        inDepthGuides: 'In-Depth Guides',
        migrations: 'Migrations',
    };

    return (
        nameMap[sectionName] ||
        sectionName
            .replace(/([A-Z])/g, ' $1') // Add spaces before capitals
            .replace(/^./, (str) => str.toUpperCase()) // Capitalize first letter
            .trim()
    );
}

/**
 * Formats bytes into human-readable format
 * @param bytes - Number of bytes
 * @returns Formatted string
 */
function formatBytes(bytes: number): string {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

// Run the generator if this file is executed directly
if (require.main === module) {
    generateLlmsTxt();
}

export { generateLlmsTxt };


================================================
FILE: teams.md/scripts/lib/content-processor.ts
================================================
import * as fs from 'fs';
import * as path from 'path';

import { FrontmatterParser } from './frontmatter-parser';
import readFileUtf8Normalized from '../../src/utils/readFileUtf8Normalized';

interface ProcessedContent {
    title: string;
    content: string;
    frontmatter: { [key: string]: any };
    filePath: string;
    sidebarPosition: number;
    relativeUrl: string;
}

interface ParsedMarkdown {
    title: string;
    content: string;
    frontmatter: { [key: string]: any };
}

interface DocusaurusConfig {
    url: string;
    baseUrl: string;
}

/**
 * Checks if a file should be ignored based on section-wide README filtering
 * @param filePath - Path to the file to check
 * @returns True if file should be ignored due to section filtering
 */
export function shouldIgnoreFileBySection(filePath: string): boolean {
    // Get the directory path
    let currentDir = path.dirname(filePath);

    // Walk up the directory tree looking for README.md or index.mdx files
    while (currentDir && currentDir !== path.dirname(currentDir)) {
        const readmePath = path.join(currentDir, 'README.md');
        const indexPath = path.join(currentDir, 'index.mdx');

        // Check README.md first, then index.mdx
        const indexFilePath = fs.existsSync(readmePath) ? readmePath : (fs.existsSync(indexPath) ? indexPath : null);

        if (indexFilePath) {
            try {
                const indexContent = readFileUtf8Normalized(indexFilePath);
                const indexFrontmatter = FrontmatterParser.extract(indexContent).frontmatter;
                // Only ignore entire section if index file has 'llms: ignore' (not 'ignore-file')
                if (indexFrontmatter.llms === 'ignore' || indexFrontmatter.llms === false) {
                    return true;
                }
            } catch (error) {
                // Ignore errors reading index file
            }
        }

        // Move up one directory
        currentDir = path.dirname(currentDir);
    }

    return false;
}

/**
 * Processes a markdown/MDX file and extracts its content
 * @param filePath - Path to the file to process
 * @param baseDir - Base directory for resolving relative paths
 * @param includeCodeBlocks - Whether to include FileCodeBlock content
 * @param fileMapping - Optional mapping of source files to generated filenames
 * @param config - Optional Docusaurus config for full URL generation
 * @param language - Optional language identifier for URL generation
 * @returns Processed content with title, content, and metadata
 */
export async function processContent(
    filePath: string,
    baseDir: string,
    includeCodeBlocks: boolean = false,
    fileMapping: Map<string, string> | null = null,
    config: DocusaurusConfig | null = null,
    language: string | null = null
): Promise<ProcessedContent | null> {
    try {
        if (!fs.existsSync(filePath)) {
            console.warn(`⚠️ File not found: ${filePath}`);
            return { title: '', content: '', frontmatter: {}, filePath, sidebarPosition: 999, relativeUrl: '' };
        }

    const rawContent = readFileUtf8Normalized(filePath);

        // Check if this file should be excluded from LLM output
        if (FrontmatterParser.shouldIgnore(rawContent)) {
            return null; // Return null to indicate this file should be skipped
        }

        // Check if language filtering is enabled and if this file is for a different language
        const { frontmatter: earlyFrontmatter } = FrontmatterParser.extract(rawContent);
        if (language && earlyFrontmatter.languages) {
            const fileLanguages = Array.isArray(earlyFrontmatter.languages)
                ? earlyFrontmatter.languages
                : [earlyFrontmatter.languages];
            if (!fileLanguages.includes(language)) {
                return null; // Skip this file as it's not for the current language
            }
        }

        const { title, content, frontmatter } = await parseMarkdownContent(rawContent, baseDir, includeCodeBlocks, filePath, fileMapping, config, language);

        // Check if this file should be ignored due to section-wide filtering
        if (shouldIgnoreFileBySection(filePath)) {
            return null; // Return null to indicate this file should be skipped
        }

        return {
            title: title,
            content: content || '',
            frontmatter: frontmatter || {},
            filePath,
            sidebarPosition: (frontmatter.sidebar_position as number) || 999,
            relativeUrl: generateRelativeUrl(filePath, baseDir)
        };
    } catch (error) {
        console.error(`❌ Error processing file ${filePath}:`, (error as Error).message);
        throw error; // Re-throw to fail the build
    }
}

/**
 * Parses markdown/MDX content and extracts title and content
 * @param rawContent - Raw file content
 * @param baseDir - Base directory for resolving paths
 * @param includeCodeBlocks - Whether to process FileCodeBlocks
 * @param filePath - Current file path for resolving relative links
 * @param fileMapping - Optional mapping of source files to generated filenames
 * @param config - Optional Docusaurus config for full URL generation
 * @param language - Optional language identifier for URL generation
 * @returns Parsed title, content, and frontmatter
 */
async function parseMarkdownContent(
    rawContent: string,
    baseDir: string,
    includeCodeBlocks: boolean,
    filePath: string,
    fileMapping: Map<string, string> | null,
    config: DocusaurusConfig | null,
    language: string | null
): Promise<ParsedMarkdown> {
    // Extract and remove frontmatter using enhanced parser with js-yaml
    const { frontmatter, content: contentWithoutFrontmatter } = FrontmatterParser.extract(rawContent);
    let content = contentWithoutFrontmatter;

    // Extract title from first H1 (always required)
    const h1Match = content.match(/^#\s+(.+)$/m);
    if (!h1Match) {
        throw new Error(`No # header found in file: ${filePath}`);
    }
    const title = h1Match[1].trim();

    // Remove import statements
    content = content.replace(/^import\s+.*$/gm, '');

    // Process FileCodeBlock components if requested
    if (includeCodeBlocks) {
        content = await processFileCodeBlocks(content, baseDir);
    } else {
        // Remove FileCodeBlock components for small version
        content = content.replace(/<FileCodeBlock[\s\S]*?\/>/g, '[Code example removed for brevity]');
    }

    // Clean up MDX-specific syntax while preserving markdown
    content = cleanMdxSyntax(content);

    // Fix internal relative links
    content = fixInternalLinks(content, filePath, fileMapping, config, language);

    // Remove excessive whitespace
    content = content.replace(/\n{3,}/g, '\n\n').trim();

    return { title, content, frontmatter };
}

/**
 * Processes FileCodeBlock components and includes the referenced code
 * @param content - Content containing FileCodeBlock components
 * @param baseDir - Base directory for resolving paths
 * @returns Content with FileCodeBlocks replaced by actual code
 */
async function processFileCodeBlocks(content: string, baseDir: string): Promise<string> {
    const fileCodeBlockRegex = /<FileCodeBlock\s+([^>]+)\/>/g;
    let processedContent = content;
    let match;

    while ((match = fileCodeBlockRegex.exec(content)) !== null) {
        const attributes = parseAttributes(match[1]);
        const { src, lang } = attributes;

        if (src) {
            try {
                const codeContent = await loadCodeFile(src, baseDir);
                const codeBlock = `\`\`\`${lang || 'typescript'}\n${codeContent}\n\`\`\``;
                processedContent = processedContent.replace(match[0], codeBlock);
            } catch (error) {
                console.warn(`⚠️ Could not load code file ${src}:`, (error as Error).message);
                processedContent = processedContent.replace(match[0], `[Code file not found: ${src}]`);
            }
        }
    }

    return processedContent;
}

/**
 * Loads code content from a file referenced by FileCodeBlock
 * @param src - Source path from FileCodeBlock (e.g., "/generated-snippets/ts/example.ts")
 * @param baseDir - Base directory
 * @returns Code content
 */
async function loadCodeFile(src: string, baseDir: string): Promise<string> {
    // Convert src path to local file path
    let filePath: string;
    if (src.startsWith('/')) {
        filePath = path.join(baseDir, 'static', src.substring(1));
    } else {
        filePath = path.join(baseDir, 'static', src);
    }

    if (fs.existsSync(filePath)) {
        return readFileUtf8Normalized(filePath).trim();
    } else {
        throw new Error(`File not found: ${filePath}`);
    }
}

/**
 * Parse JSX-style attributes from attribute string
 * @param attributeString - String containing attributes
 * @returns Parsed attributes
 */
function parseAttributes(attributeString: string): { [key: string]: string } {
    const attributes: { [key: string]: string } = {};
    const regex = /(\w+)=["']([^"']+)["']/g;
    let match;

    while ((match = regex.exec(attributeString)) !== null) {
        attributes[match[1]] = match[2];
    }

    return attributes;
}

/**
 * Cleans MDX-specific syntax while preserving standard markdown
 * @param content - Content to clean
 * @returns Cleaned content
 */
function cleanMdxSyntax(content: string): string {
    let cleaned = content;

    // Remove HTML comments from llms.txt output
    // Generated .mdx files contain AUTO-GENERATED warnings as HTML comments for developers,
    // but these developer notes don't belong in AI-friendly documentation files.
    // Note: Section markers (<!-- section-name -->) in .incl.md source files are processed
    // earlier by generate-language-docs.ts and never appear in generated .mdx files.
    cleaned = cleaned.replace(/<!--[\s\S]*?-->/g, '');

    // Remove JSX components (except code blocks which are handled separately)
    cleaned = cleaned.replace(/<\/?[A-Z][^>]*>/g, '');

    // Remove empty JSX fragments
    cleaned = cleaned.replace(/<>\s*<\/>/g, '');

    // Remove JSX expressions but keep the content if it's simple text
    // IMPORTANT: Don't process content inside code blocks (```)
    const codeBlockRegex = /```[\s\S]*?```/g;
    const codeBlocks: string[] = [];

    // Extract code blocks temporarily
    cleaned = cleaned.replace(codeBlockRegex, (match) => {
        codeBlocks.push(match);
        return `___CODE_BLOCK_${codeBlocks.length - 1}___`;
    });

    // Now remove JSX expressions outside code blocks
    cleaned = cleaned.replace(/\{([^{}]+)\}/g, (match, expr) => {
        // Keep simple text expressions, remove complex ones
        if (expr.includes('(') || expr.includes('.') || expr.includes('[')) {
            return '';
        }
        return expr;
    });

    // Restore code blocks
    cleaned = cleaned.replace(/___CODE_BLOCK_(\d+)___/g, (match, index) => {
        return codeBlocks[parseInt(index)];
    });

    // Clean up multiple empty lines
    cleaned = cleaned.replace(/\n\s*\n\s*\n/g, '\n\n');

    return cleaned;
}


/**
 * Generates a relative URL for a documentation file
 * @param filePath - Full path to the file
 * @param baseDir - Base directory path
 * @returns Relative URL for the file
 */
export function generateRelativeUrl(filePath: string, baseDir: string): string {
    const relativePath = path.relative(path.join(baseDir, 'docs'), filePath);

    // Convert file path to URL format
    let url = relativePath
        .replace(/\\/g, '/') // Convert Windows paths
        .replace(/\.mdx?$/, '') // Remove .md/.mdx extension
        .replace(/\/README$/i, '') // Remove /README from end
        .replace(/\/index$/i, ''); // Remove /index from end

    // Add leading slash
    if (!url.startsWith('/')) {
        url = '/' + url;
    }

    // Handle empty URL (root README)
    if (url === '/') {
        url = '';
    }

    return url;
}

/**
 * Fixes internal relative links to point to generated .txt files
 * @param content - Content containing markdown links
 * @param currentFilePath - Path of the current file being processed
 * @param fileMapping - Optional mapping of source files to generated filenames
 * @param config - Optional Docusaurus config for full URL generation
 * @param language - Optional language identifier for URL generation
 * @returns Content with fixed links
 */
export function fixInternalLinks(
    content: string,
    currentFilePath: string,
    fileMapping: Map<string, string> | null,
    config: DocusaurusConfig | null,
    language: string | null
): string {
    // Pattern to match markdown links: [text](link)
    const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;

    return content.replace(linkRegex, (match, text, link) => {
        // Skip external links (http/https/mailto/etc)
        if (link.startsWith('http') || link.startsWith('mailto') || link.startsWith('#')) {
            return match;
        }

        // Skip absolute paths starting with /
        if (link.startsWith('/') && !link.startsWith('//')) {
            return match;
        }

        // Handle relative links
        if (!link.includes('://')) {
            // Remove any file extensions and anchors
            const cleanLink = link.split('#')[0].replace(/\.(md|mdx)$/, '');

            // If it's just a filename without path separators, it's likely a sibling file
            if (!cleanLink.includes('/')) {
                // Try to resolve using file mapping first
                if (fileMapping) {
                    const currentDir = path.dirname(currentFilePath);
                    const possiblePath = path.join(currentDir, clean
Download .txt
gitextract_6wy_q17s/

├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── deploy-teams-docs.yml
├── .gitignore
├── .gitmodules
├── .prettierignore
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── package.json
├── packages/
│   └── README.md
├── prettier.config.js
├── teams.md/
│   ├── .gitattributes
│   ├── .gitignore
│   ├── LANGUAGE-INCLUDE.md
│   ├── README.md
│   ├── docs/
│   │   └── main/
│   │       ├── developer-tools/
│   │       │   ├── README.md
│   │       │   ├── _category_.json
│   │       │   ├── cli.md
│   │       │   └── devtools/
│   │       │       ├── README.md
│   │       │       ├── cards.md
│   │       │       ├── chat.md
│   │       │       └── inspect.md
│   │       ├── privacy.md
│   │       ├── teams/
│   │       │   ├── README.md
│   │       │   ├── _category_.json
│   │       │   ├── app-authentication/
│   │       │   │   ├── README.mdx
│   │       │   │   ├── _category_.json
│   │       │   │   ├── client-secret.md
│   │       │   │   ├── federated-identity-credentials.md
│   │       │   │   ├── troubleshooting.md
│   │       │   │   └── user-managed-identity.md
│   │       │   ├── configuration/
│   │       │   │   ├── README.md
│   │       │   │   ├── _category_.json
│   │       │   │   ├── agents-toolkit.md
│   │       │   │   └── manual-configuration.mdx
│   │       │   ├── core-concepts.md
│   │       │   ├── enabling-in-copilot.md
│   │       │   ├── manifest.md
│   │       │   └── user-authentication/
│   │       │       ├── README.md
│   │       │       ├── _category_.json
│   │       │       ├── sso-setup.mdx
│   │       │       └── troubleshooting-sso.mdx
│   │       ├── welcome.mdx
│   │       └── why.md
│   ├── docusaurus.config.ts
│   ├── i18n/
│   │   └── en/
│   │       ├── code.json
│   │       ├── docusaurus-plugin-content-docs/
│   │       │   └── current.json
│   │       ├── docusaurus-plugin-content-docs-csharp/
│   │       │   └── current.json
│   │       ├── docusaurus-plugin-content-docs-typescript/
│   │       │   └── current.json
│   │       └── docusaurus-theme-classic/
│   │           ├── footer.json
│   │           └── navbar.json
│   ├── package.json
│   ├── scripts/
│   │   ├── generate-language-docs.ts
│   │   ├── generate-llms-txt.ts
│   │   └── lib/
│   │       ├── content-processor.ts
│   │       ├── file-collector.ts
│   │       └── frontmatter-parser.ts
│   ├── sidebars.ts
│   ├── src/
│   │   ├── components/
│   │   │   ├── FileCodeBlock.tsx
│   │   │   ├── LangLink.tsx
│   │   │   ├── Language.tsx
│   │   │   ├── LanguageBanner.tsx
│   │   │   ├── LanguageDropdown.tsx
│   │   │   └── include/
│   │   │       ├── essentials/
│   │   │       │   ├── api/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── app-authentication/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── csharp.incl.md
│   │   │       │   ├── graph/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── on-activity/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── on-event/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── python.incl.md
│   │   │       │   ├── sending-messages/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── proactive-messaging/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   └── typescript.incl.md
│   │   │       ├── getting-started/
│   │   │       │   ├── _LLMs/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── code-basics/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── csharp.incl.md
│   │   │       │   ├── python.incl.md
│   │   │       │   ├── quickstart/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── running-in-teams/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   └── typescript.incl.md
│   │   │       ├── in-depth-guides/
│   │   │       │   ├── adaptive-cards/
│   │   │       │   │   ├── building-adaptive-cards/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── executing-actions/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── ai/
│   │   │       │   │   ├── a2a/
│   │   │       │   │   │   ├── a2a-client/
│   │   │       │   │   │   │   ├── python.incl.md
│   │   │       │   │   │   │   └── typescript.incl.md
│   │   │       │   │   │   ├── a2a-server/
│   │   │       │   │   │   │   ├── python.incl.md
│   │   │       │   │   │   │   └── typescript.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── best-practices/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── chat/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── function-calling/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── keeping-state/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── mcp/
│   │   │       │   │   │   ├── mcp-client/
│   │   │       │   │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   │   ├── python.incl.md
│   │   │       │   │   │   │   └── typescript.incl.md
│   │   │       │   │   │   └── mcp-server/
│   │   │       │   │   │       ├── csharp.incl.md
│   │   │       │   │   │       ├── python.incl.md
│   │   │       │   │   │       └── typescript.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   ├── setup-and-prereqs/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── csharp.incl.md
│   │   │       │   ├── dialogs/
│   │   │       │   │   ├── creating-dialogs/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── handling-dialog-submissions/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── handling-multi-step-forms/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── feedback/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── meeting-events/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── python.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── message-extensions/
│   │   │       │   │   ├── action-commands/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── link-unfurling/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   ├── search-commands/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── settings/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── observability/
│   │   │       │   │   ├── logging/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── middleware/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── python.incl.md
│   │   │       │   ├── server/
│   │   │       │   │   ├── http-server/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   ├── python.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── static-pages/
│   │   │       │   │       ├── csharp.incl.md
│   │   │       │   │       ├── python.incl.md
│   │   │       │   │       └── typescript.incl.md
│   │   │       │   ├── tabs/
│   │   │       │   │   ├── csharp.incl.md
│   │   │       │   │   ├── functions/
│   │   │       │   │   │   ├── csharp.incl.md
│   │   │       │   │   │   └── typescript.incl.md
│   │   │       │   │   └── typescript.incl.md
│   │   │       │   ├── typescript.incl.md
│   │   │       │   └── user-authentication/
│   │   │       │       ├── csharp.incl.md
│   │   │       │       ├── python.incl.md
│   │   │       │       └── typescript.incl.md
│   │   │       └── migrations/
│   │   │           ├── botbuilder/
│   │   │           │   ├── integration/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   ├── proactive-activities/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   ├── sending-activities/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   ├── the-api-client/
│   │   │           │   │   ├── csharp.incl.md
│   │   │           │   │   ├── python.incl.md
│   │   │           │   │   └── typescript.incl.md
│   │   │           │   └── user-authentication/
│   │   │           │       ├── csharp.incl.md
│   │   │           │       ├── python.incl.md
│   │   │           │       └── typescript.incl.md
│   │   │           ├── slack-bolt/
│   │   │           │   └── typescript.incl.md
│   │   │           ├── v1/
│   │   │           │   ├── python.incl.md
│   │   │           │   └── typescript.incl.md
│   │   │           └── v2-previews/
│   │   │               └── typescript.incl.md
│   │   ├── constants/
│   │   │   └── languages.ts
│   │   ├── css/
│   │   │   ├── code-blocks.css
│   │   │   └── custom.css
│   │   ├── hooks/
│   │   │   └── useLanguagePreference.tsx
│   │   ├── pages/
│   │   │   ├── csharp.tsx
│   │   │   ├── index.module.css
│   │   │   ├── index.tsx
│   │   │   ├── python.tsx
│   │   │   ├── templates/
│   │   │   │   ├── essentials/
│   │   │   │   │   ├── README.mdx
│   │   │   │   │   ├── _category_.json
│   │   │   │   │   ├── api.mdx
│   │   │   │   │   ├── app-authentication.mdx
│   │   │   │   │   ├── app-basics.mdx
│   │   │   │   │   ├── graph.mdx
│   │   │   │   │   ├── on-activity/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   └── activity-ref.mdx
│   │   │   │   │   ├── on-event.mdx
│   │   │   │   │   └── sending-messages/
│   │   │   │   │       ├── README.mdx
│   │   │   │   │       ├── _category_.json
│   │   │   │   │       └── proactive-messaging.mdx
│   │   │   │   ├── getting-started/
│   │   │   │   │   ├── README.mdx
│   │   │   │   │   ├── _LLMs.mdx
│   │   │   │   │   ├── _category_.json
│   │   │   │   │   ├── code-basics.mdx
│   │   │   │   │   ├── quickstart.mdx
│   │   │   │   │   └── running-in-teams/
│   │   │   │   │       ├── README.mdx
│   │   │   │   │       └── _category_.json
│   │   │   │   ├── in-depth-guides/
│   │   │   │   │   ├── README.mdx
│   │   │   │   │   ├── _category_.json
│   │   │   │   │   ├── adaptive-cards/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── building-adaptive-cards.mdx
│   │   │   │   │   │   └── executing-actions.mdx
│   │   │   │   │   ├── ai/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── a2a/
│   │   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   │   ├── a2a-client.mdx
│   │   │   │   │   │   │   └── a2a-server.mdx
│   │   │   │   │   │   ├── best-practices.mdx
│   │   │   │   │   │   ├── chat.mdx
│   │   │   │   │   │   ├── function-calling.mdx
│   │   │   │   │   │   ├── keeping-state.mdx
│   │   │   │   │   │   ├── mcp/
│   │   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   │   ├── mcp-client.mdx
│   │   │   │   │   │   │   └── mcp-server.mdx
│   │   │   │   │   │   └── setup-and-prereqs.mdx
│   │   │   │   │   ├── dialogs/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── creating-dialogs.mdx
│   │   │   │   │   │   ├── handling-dialog-submissions.mdx
│   │   │   │   │   │   └── handling-multi-step-forms.mdx
│   │   │   │   │   ├── feedback.mdx
│   │   │   │   │   ├── meeting-events.mdx
│   │   │   │   │   ├── message-extensions/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── action-commands.mdx
│   │   │   │   │   │   ├── link-unfurling.mdx
│   │   │   │   │   │   ├── search-commands.mdx
│   │   │   │   │   │   └── settings.mdx
│   │   │   │   │   ├── observability/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── logging.mdx
│   │   │   │   │   │   └── middleware.mdx
│   │   │   │   │   ├── server/
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── http-server.mdx
│   │   │   │   │   │   └── static-pages.mdx
│   │   │   │   │   ├── tabs/
│   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   ├── _category_.json
│   │   │   │   │   │   ├── app-options.mdx
│   │   │   │   │   │   ├── functions/
│   │   │   │   │   │   │   ├── README.mdx
│   │   │   │   │   │   │   └── function-calling.mdx
│   │   │   │   │   │   ├── getting-started.mdx
│   │   │   │   │   │   ├── graph.mdx
│   │   │   │   │   │   └── using-the-app.mdx
│   │   │   │   │   └── user-authentication.mdx
│   │   │   │   └── migrations/
│   │   │   │       ├── README.mdx
│   │   │   │       ├── _category_.json
│   │   │   │       ├── botbuilder/
│   │   │   │       │   ├── README.mdx
│   │   │   │       │   ├── _category_.json
│   │   │   │       │   ├── integration.mdx
│   │   │   │       │   ├── proactive-activities.mdx
│   │   │   │       │   ├── sending-activities.mdx
│   │   │   │       │   ├── the-api-client.mdx
│   │   │   │       │   └── user-authentication.mdx
│   │   │   │       ├── slack-bolt.mdx
│   │   │   │       ├── v1.mdx
│   │   │   │       └── v2-previews.mdx
│   │   │   └── typescript.tsx
│   │   ├── scripts/
│   │   │   └── scaffold.js
│   │   ├── theme/
│   │   │   ├── DocSidebarItems/
│   │   │   │   └── index.tsx
│   │   │   ├── Navbar/
│   │   │   │   └── Content/
│   │   │   │       └── index.tsx
│   │   │   ├── PaginatorNavLink/
│   │   │   │   └── index.tsx
│   │   │   └── Root.tsx
│   │   └── utils/
│   │       ├── languageUtils.ts
│   │       ├── normalizePath.ts
│   │       ├── pageAvailability.ts
│   │       └── readFileUtf8Normalized.ts
│   ├── static/
│   │   ├── .nojekyll
│   │   ├── llms_docs/
│   │   │   └── llms.txt
│   │   ├── missing-pages.json
│   │   └── scripts/
│   │       └── clarity.js
│   └── tsconfig.json
└── turbo.json
Download .txt
SYMBOL INDEX (116 symbols across 25 files)

FILE: teams.md/scripts/generate-language-docs.ts
  constant TEMPLATES_DIR (line 22) | const TEMPLATES_DIR = path.join(__dirname, '..', 'src', 'pages', 'templa...
  constant FRAGMENTS_DIR (line 23) | const FRAGMENTS_DIR = path.join(__dirname, '..', 'src', 'components', 'i...
  constant DOCS_BASE (line 25) | const DOCS_BASE = path.join(__dirname, '..', 'docs', 'main');
  constant NOT_APPLICABLE_REGEX (line 35) | const NOT_APPLICABLE_REGEX = /^(not applicable|n\/a)\s*$/i;
  constant LANGUAGE_INCLUDE_REGEX (line 42) | const LANGUAGE_INCLUDE_REGEX = /<LanguageInclude\s+(?:section="([^"]+)"|...
  constant LANGUAGE_INCL_FILENAME_REGEX (line 45) | const LANGUAGE_INCL_FILENAME_REGEX = new RegExp(`^(${languagePattern})\\...
  function extractSection (line 54) | function extractSection(markdown: string, sectionName: string): string |...
  function getIncludeFilePath (line 84) | function getIncludeFilePath(templatePath: string, language: Language): s...
  function getTemplatePathFromInclude (line 100) | function getTemplatePathFromInclude(includePath: string): string {
  function processLanguageIncludeTags (line 117) | function processLanguageIncludeTags(
  function deleteInDirectory (line 325) | function deleteInDirectory(dir: string, deletedCount: { count: number })...
  function cleanGeneratedFiles (line 354) | function cleanGeneratedFiles(): void {
  function cleanGeneratedFilesForTemplate (line 389) | function cleanGeneratedFilesForTemplate(templatePath: string): void {
  function shouldGenerateForLanguage (line 410) | function shouldGenerateForLanguage(templateContent: string, language: La...
  function generateDocsForTemplate (line 427) | function generateDocsForTemplate(templatePath: string): void {
  function copyCategoryFiles (line 518) | function copyCategoryFiles(): void {
  function findTemplateFiles (line 559) | function findTemplateFiles(): string[] {
  function createLanguageRootCategories (line 595) | function createLanguageRootCategories(): void {
  function warnOrphanedIncludeFiles (line 626) | function warnOrphanedIncludeFiles() {
  function writePageManifest (line 658) | function writePageManifest(): void {
  function writeContentGapsManifest (line 678) | function writeContentGapsManifest(): void {
  type GenerationResult (line 726) | interface GenerationResult {
  function generateAll (line 735) | function generateAll(): GenerationResult {
  function watch (line 782) | function watch(): void {

FILE: teams.md/scripts/generate-llms-txt.ts
  constant LANGUAGE_SPECIFIC_TIPS (line 12) | const LANGUAGE_SPECIFIC_TIPS: Record<Language, string[]> = {
  type DocusaurusConfig (line 41) | interface DocusaurusConfig {
  type ProcessedFile (line 46) | interface ProcessedFile {
  type FileInfo (line 55) | interface FileInfo {
  type FolderStructure (line 62) | interface FolderStructure {
  function getDocusaurusConfig (line 75) | function getDocusaurusConfig(baseDir: string): DocusaurusConfig {
  function generateLlmsTxt (line 101) | async function generateLlmsTxt(): Promise<void> {
  function generateLanguageFiles (line 140) | async function generateLanguageFiles(language: Language, baseDir: string...
  function processAllFiles (line 192) | async function processAllFiles(allFiles: string[], baseDir: string, lang...
  function generateIndividualTxtFiles (line 245) | async function generateIndividualTxtFiles(
  function generateSmallVersionHierarchical (line 303) | async function generateSmallVersionHierarchical(language: Language, base...
  function renderHierarchicalStructure (line 331) | function renderHierarchicalStructure(structure: { [key: string]: FolderS...
  function extractSummaryFromFile (line 462) | function extractSummaryFromFile(filePath: string): string {
  function generateFullVersion (line 506) | async function generateFullVersion(language: Language, processedFiles: P...
  function groupFilesBySection (line 536) | function groupFilesBySection(processedFiles: ProcessedFile[], baseDir: s...
  function generateSafeFileName (line 593) | function generateSafeFileName(title: string): string {
  function formatSectionName (line 611) | function formatSectionName(sectionName: string): string {
  function formatBytes (line 634) | function formatBytes(bytes: number): string {

FILE: teams.md/scripts/lib/content-processor.ts
  type ProcessedContent (line 7) | interface ProcessedContent {
  type ParsedMarkdown (line 16) | interface ParsedMarkdown {
  type DocusaurusConfig (line 22) | interface DocusaurusConfig {
  function shouldIgnoreFileBySection (line 32) | function shouldIgnoreFileBySection(filePath: string): boolean {
  function processContent (line 74) | async function processContent(
  function parseMarkdownContent (line 138) | async function parseMarkdownContent(
  function processFileCodeBlocks (line 187) | async function processFileCodeBlocks(content: string, baseDir: string): ...
  function loadCodeFile (line 217) | async function loadCodeFile(src: string, baseDir: string): Promise<strin...
  function parseAttributes (line 238) | function parseAttributes(attributeString: string): { [key: string]: stri...
  function cleanMdxSyntax (line 255) | function cleanMdxSyntax(content: string): string {
  function generateRelativeUrl (line 309) | function generateRelativeUrl(filePath: string, baseDir: string): string {
  function fixInternalLinks (line 341) | function fixInternalLinks(
  function extractSummary (line 429) | function extractSummary(content: string, maxLength: number = 200): string {

FILE: teams.md/scripts/lib/file-collector.ts
  type FileInfo (line 7) | interface FileInfo {
  type FolderStructure (line 14) | interface FolderStructure {
  type HierarchicalFiles (line 22) | interface HierarchicalFiles {
  function collectFiles (line 32) | function collectFiles(dirPath: string, extensions: string[] = ['.md', '....
  function shouldSkipDirectory (line 75) | function shouldSkipDirectory(dirName: string): boolean {
  function getHierarchicalFiles (line 96) | function getHierarchicalFiles(basePath: string, language: string): Hiera...
  function buildHierarchicalStructure (line 111) | function buildHierarchicalStructure(rootPath: string): { [key: string]: ...
  function getPriorityFiles (line 273) | function getPriorityFiles(organized: any): string[] {

FILE: teams.md/scripts/lib/frontmatter-parser.ts
  constant FRONTMATTER_REGEX (line 10) | const FRONTMATTER_REGEX = /^---\s*\r?\n([\s\S]*?)\r?\n---/;
  type FrontmatterData (line 12) | interface FrontmatterData {
  type ExtractResult (line 16) | interface ExtractResult {
  class FrontmatterParser (line 25) | class FrontmatterParser {
    method extract (line 31) | static extract(content: string): ExtractResult {
    method parseSimple (line 71) | static parseSimple(frontmatterText: string): FrontmatterData {
    method extractFromFile (line 94) | static extractFromFile(filePath: string): ExtractResult | null {
    method getProperty (line 115) | static getProperty<T = any>(content: string, propertyName: string, def...
    method shouldIgnore (line 136) | static shouldIgnore(content: string): boolean {
    method _parseValue (line 156) | private static _parseValue(value: string): string | number | boolean {

FILE: teams.md/src/components/FileCodeBlock.tsx
  type FileCodeBlockParams (line 5) | type FileCodeBlockParams = {
  function FileCodeBlock (line 10) | function FileCodeBlock({ src, lang }: PropsWithChildren<FileCodeBlockPar...

FILE: teams.md/src/components/LangLink.tsx
  type LangLinkProps (line 5) | interface LangLinkProps {
  function LangLink (line 17) | function LangLink({ to, children }: PropsWithChildren<LangLinkProps>) {

FILE: teams.md/src/components/Language.tsx
  type LanguageProps (line 5) | type LanguageProps = {
  function Language (line 10) | function Language({ language, children }: PropsWithChildren<LanguageProp...

FILE: teams.md/src/components/LanguageBanner.tsx
  type LanguageBannerProps (line 5) | interface LanguageBannerProps {
  function LanguageBanner (line 11) | function LanguageBanner({

FILE: teams.md/src/components/LanguageDropdown.tsx
  type LanguageDropdownProps (line 16) | interface LanguageDropdownProps {
  function LanguageDropdown (line 24) | function LanguageDropdown(props: LanguageDropdownProps) {

FILE: teams.md/src/constants/languages.ts
  constant LANGUAGES (line 5) | const LANGUAGES = ['typescript', 'csharp', 'python'] as const;
  type Language (line 6) | type Language = (typeof LANGUAGES)[number];
  constant LANGUAGE_NAMES (line 8) | const LANGUAGE_NAMES = {
  constant DEFAULT_LANGUAGE (line 14) | const DEFAULT_LANGUAGE: Language = 'typescript';
  type LanguageAvailabilityMap (line 20) | interface LanguageAvailabilityMap {

FILE: teams.md/src/hooks/useLanguagePreference.tsx
  type LanguageContextProps (line 12) | interface LanguageContextProps {
  constant STORAGE_KEY (line 19) | const STORAGE_KEY = 'teams-sdk-language-preference';
  function LanguageProvider (line 42) | function LanguageProvider({ children }: { children: ReactNode }) {
  function useLanguagePreference (line 85) | function useLanguagePreference(): LanguageContextProps {

FILE: teams.md/src/pages/csharp.tsx
  function CSharp (line 4) | function CSharp() {

FILE: teams.md/src/pages/index.tsx
  function Home (line 3) | function Home() {

FILE: teams.md/src/pages/python.tsx
  function Python (line 4) | function Python() {

FILE: teams.md/src/pages/typescript.tsx
  function Typescript (line 4) | function Typescript() {

FILE: teams.md/src/scripts/scaffold.js
  function ensureDirSync (line 6) | function ensureDirSync(dir) {
  function createFileIfNotExists (line 12) | function createFileIfNotExists(filePath, content = '') {
  function scaffold (line 19) | function scaffold(userInput) {
  function isValidPath (line 103) | function isValidPath(p) {

FILE: teams.md/src/theme/DocSidebarItems/index.tsx
  function buildItemsSignature (line 10) | function buildItemsSignature(items: Props['items']): string {
  function DocSidebarItems (line 28) | function DocSidebarItems(props: Props): React.JSX.Element {

FILE: teams.md/src/theme/Navbar/Content/index.tsx
  function useNavbarItems (line 13) | function useNavbarItems() {
  function NavbarItems (line 17) | function NavbarItems({ items }) {
  function NavbarContentLayout (line 27) | function NavbarContentLayout({ left, right }) {
  function NavbarContent (line 36) | function NavbarContent(): React.JSX.Element {

FILE: teams.md/src/theme/PaginatorNavLink/index.tsx
  function PaginatorNavLink (line 9) | function PaginatorNavLink(props: Props): React.JSX.Element {

FILE: teams.md/src/theme/Root.tsx
  function Root (line 5) | function Root({ children }: { children: ReactNode }): React.JSX.Element {

FILE: teams.md/src/utils/languageUtils.ts
  function createLanguagePattern (line 8) | function createLanguagePattern(baseUrl: string): RegExp {
  function getLanguageFromPath (line 18) | function getLanguageFromPath(pathname: string, baseUrl: string): Language {
  function getLanguageFromPathStrict (line 30) | function getLanguageFromPathStrict(pathname: string, baseUrl: string): L...
  function replaceLanguageInPath (line 43) | function replaceLanguageInPath(
  function getManifestPathFromUrl (line 64) | function getManifestPathFromUrl(pathname: string, baseUrl: string): stri...

FILE: teams.md/src/utils/normalizePath.ts
  function normalizePath (line 4) | function normalizePath(path: string) {

FILE: teams.md/src/utils/pageAvailability.ts
  function isPageAvailableForLanguage (line 12) | async function isPageAvailableForLanguage(pagePath: string, language: La...

FILE: teams.md/src/utils/readFileUtf8Normalized.ts
  function readFileUtf8Normalized (line 7) | function readFileUtf8Normalized(filePath: string): string {
Condensed preview — 318 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (944K chars).
[
  {
    "path": ".github/workflows/ci.yml",
    "chars": 728,
    "preview": "name: CI\n\non:\n  pull_request:\n      branches:\n        - main\n      paths:\n        - 'teams.md/**'\n\njobs:\n  build-teams-m"
  },
  {
    "path": ".github/workflows/deploy-teams-docs.yml",
    "chars": 1387,
    "preview": "name: Deploy-Teams-Docs\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n    paths:\n      - 'teams.md/**'\n   "
  },
  {
    "path": ".gitignore",
    "chars": 528,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# Dependencies\nnode_modules\n.pnp\n"
  },
  {
    "path": ".gitmodules",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".prettierignore",
    "chars": 27,
    "preview": "dist\nnode_modules\ncoverage\n"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 67,
    "preview": "{\n  \"recommendations\": [\"streetsidesoftware.code-spell-checker\"]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 92,
    "preview": "{\n  \"cSpell.words\": [\n    \"botframework\",\n    \"devtunnels\",\n    \"Entra\",\n    \"mdbook\"\n  ]\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3025,
    "preview": "# Instructions for Contributing Code\n\nTeams SDK is a mono-repo that hosts GitHub submodules to other repos that contain "
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "Copyright (c) Microsoft Corporation.\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining"
  },
  {
    "path": "README.md",
    "chars": 4194,
    "preview": "# Welcome to the Teams SDK ([Docs](https://microsoft.github.io/teams-sdk/))\n\nTeams SDK represents a fundamental reimagin"
  },
  {
    "path": "SECURITY.md",
    "chars": 2640,
    "preview": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products an"
  },
  {
    "path": "package.json",
    "chars": 836,
    "preview": "{\n  \"name\": \"teams-sdk\",\n  \"private\": true,\n  \"scripts\": {\n    \"clean\": \"npx turbo clean\",\n    \"build\": \"npx turbo build"
  },
  {
    "path": "packages/README.md",
    "chars": 119,
    "preview": "# This is a blank file\n\nThis is a blank folder currently. We will add packages that are common to all submodules here.\n"
  },
  {
    "path": "prettier.config.js",
    "chars": 304,
    "preview": "// prettier.config.js, .prettierrc.js, prettier.config.cjs, or .prettierrc.cjs\n\n/**\n * @see https://prettier.io/docs/en/"
  },
  {
    "path": "teams.md/.gitattributes",
    "chars": 66,
    "preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": "teams.md/.gitignore",
    "chars": 270,
    "preview": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\nscripts/generated/\n\n# Mis"
  },
  {
    "path": "teams.md/LANGUAGE-INCLUDE.md",
    "chars": 9166,
    "preview": "# Language-Specific Documentation System\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Architecture](#architec"
  },
  {
    "path": "teams.md/README.md",
    "chars": 1387,
    "preview": "# Website\n\nThis website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.\n\n### Ins"
  },
  {
    "path": "teams.md/docs/main/developer-tools/README.md",
    "chars": 705,
    "preview": "---\nsidebar_position: 4\nsummary: Overview of developer tools in Teams SDK including the CLI for project management and D"
  },
  {
    "path": "teams.md/docs/main/developer-tools/_category_.json",
    "chars": 71,
    "preview": "{\n  \"position\": 5,\n  \"label\": \"Developer Tools\",\n  \"collapsed\": true\n}\n"
  },
  {
    "path": "teams.md/docs/main/developer-tools/cli.md",
    "chars": 4884,
    "preview": "---\nsidebar_position: 1\nsummary: Comprehensive guide to the Teams CLI tool for creating, managing, and deploying Teams S"
  },
  {
    "path": "teams.md/docs/main/developer-tools/devtools/README.md",
    "chars": 998,
    "preview": "---\nsidebar_position: 2\nsummary: Use DevTools to locally test Teams apps with chat, activity inspection, and card design"
  },
  {
    "path": "teams.md/docs/main/developer-tools/devtools/cards.md",
    "chars": 1614,
    "preview": "---\nsidebar_position: 3\nsummary: Design and test Adaptive Cards using the DevTools card designer with live preview and J"
  },
  {
    "path": "teams.md/docs/main/developer-tools/devtools/chat.md",
    "chars": 5314,
    "preview": "---\nsidebar_position: 1\nsummary: Test chat functionality with your Teams agent using the lightweight DevTools without si"
  },
  {
    "path": "teams.md/docs/main/developer-tools/devtools/inspect.md",
    "chars": 2237,
    "preview": "---\nsidebar_position: 2\nsummary: Inspect all incoming and outgoing activities with your agent using DevTools Activities "
  },
  {
    "path": "teams.md/docs/main/privacy.md",
    "chars": 809,
    "preview": "---\nsidebar_position: 5\nsummary: Privacy policy detailing data collection practices using Microsoft Clarity for website "
  },
  {
    "path": "teams.md/docs/main/teams/README.md",
    "chars": 1272,
    "preview": "---\nsidebar_position: 3\nsummary: Overview of Teams-specific features and SDK components that enable agent integration wi"
  },
  {
    "path": "teams.md/docs/main/teams/_category_.json",
    "chars": 74,
    "preview": "{\n  \"position\": 2,\n  \"label\": \"Teams Integration\",\n  \"collapsed\": false\n}\n"
  },
  {
    "path": "teams.md/docs/main/teams/app-authentication/README.mdx",
    "chars": 1403,
    "preview": "---\nsidebar_position: 4\nsummary: Set up authentication for your Teams bot using client secrets, user managed identities,"
  },
  {
    "path": "teams.md/docs/main/teams/app-authentication/_category_.json",
    "chars": 88,
    "preview": "{\n  \"label\": \"App Authentication Configuration\",\n  \"position\": 3,\n  \"collapsed\": true\n}\n"
  },
  {
    "path": "teams.md/docs/main/teams/app-authentication/client-secret.md",
    "chars": 1659,
    "preview": "---\nsidebar_position: 1\ntitle: Client Secret Setup\nsummary: Set up client secret authentication for your Teams bot in Az"
  },
  {
    "path": "teams.md/docs/main/teams/app-authentication/federated-identity-credentials.md",
    "chars": 3449,
    "preview": "---\nsidebar_position: 3\ntitle: Federated Identity Credentials Setup\nsummary: Set up Federated Identity Credentials authe"
  },
  {
    "path": "teams.md/docs/main/teams/app-authentication/troubleshooting.md",
    "chars": 4269,
    "preview": "---\nsidebar_position: 4\ntitle: Troubleshooting\nsummary: Common authentication errors and how to resolve them\nllms: ignor"
  },
  {
    "path": "teams.md/docs/main/teams/app-authentication/user-managed-identity.md",
    "chars": 2226,
    "preview": "---\nsidebar_position: 2\ntitle: User Managed Identity Setup\nsummary: Set up User Managed Identity authentication for your"
  },
  {
    "path": "teams.md/docs/main/teams/configuration/README.md",
    "chars": 492,
    "preview": "# Basic Configuration\n\nAfter learning about the [core concepts](./../core-concepts) on how to enable an application in T"
  },
  {
    "path": "teams.md/docs/main/teams/configuration/_category_.json",
    "chars": 75,
    "preview": "{\n  \"position\": 2,\n  \"label\": \"Basic Configuration\",\n  \"collapsed\": true\n}\n"
  },
  {
    "path": "teams.md/docs/main/teams/configuration/agents-toolkit.md",
    "chars": 2224,
    "preview": "---\nsidebar_position: 1\nsummary: Automate Teams app development with Microsoft 365 Agents Toolkit for manifest managemen"
  },
  {
    "path": "teams.md/docs/main/teams/configuration/manual-configuration.mdx",
    "chars": 4675,
    "preview": "---\nsidebar_position: 2\nsummary: Describe how to deploy the Azure Bot Service resource required for Teams bot apps\n---\n\n"
  },
  {
    "path": "teams.md/docs/main/teams/core-concepts.md",
    "chars": 5591,
    "preview": "---\nsidebar_position: 1\nsummary: Understand Teams app architecture including app registration, Azure Bot Service, DevTun"
  },
  {
    "path": "teams.md/docs/main/teams/enabling-in-copilot.md",
    "chars": 3797,
    "preview": "---\nsidebar_position: 6\nsummary: Learn how to enable your Teams app to work in M365 Copilot by updating the app manifest"
  },
  {
    "path": "teams.md/docs/main/teams/manifest.md",
    "chars": 1671,
    "preview": "---\nsidebar_position: 5\nsummary: Learn about Teams app manifest requirements, permissions, and sideloading process for a"
  },
  {
    "path": "teams.md/docs/main/teams/user-authentication/README.md",
    "chars": 6668,
    "preview": "---\nsidebar_position: 4\nsummary: Overview of user authentication in Teams SDK applications, including OAuth, SSO, and se"
  },
  {
    "path": "teams.md/docs/main/teams/user-authentication/_category_.json",
    "chars": 94,
    "preview": "{\n  \"label\": \"User Authentication Configuration\",\n    \"collapsed\": true,\n    \"position\": 4,\n}\n"
  },
  {
    "path": "teams.md/docs/main/teams/user-authentication/sso-setup.mdx",
    "chars": 4082,
    "preview": "---\nsidebar_position: 1\nsummary: Describes how to configure SSO in Teams\n---\n\n# SSO Setup\n\nThis section describes how to"
  },
  {
    "path": "teams.md/docs/main/teams/user-authentication/troubleshooting-sso.mdx",
    "chars": 2865,
    "preview": "---\nsidebar_position: 2\ntitle: Troubleshooting\nsummary: Common SSO errors and how to resolve them\n---\n\nimport LangLink f"
  },
  {
    "path": "teams.md/docs/main/welcome.mdx",
    "chars": 1958,
    "preview": "---\nsidebar_position: 0\nsummary: Welcome guide to Teams SDK, covering the quickstart process and how to build agents and"
  },
  {
    "path": "teams.md/docs/main/why.md",
    "chars": 5747,
    "preview": "---\nsidebar_position: 1\nsummary: Explanation of why an SDK is beneficial for building Teams agent applications, covering"
  },
  {
    "path": "teams.md/docusaurus.config.ts",
    "chars": 7145,
    "preview": "import type * as Preset from '@docusaurus/preset-classic';\nimport type { Config } from '@docusaurus/types';\nimport path "
  },
  {
    "path": "teams.md/i18n/en/code.json",
    "chars": 12952,
    "preview": "{\n  \"theme.ErrorPageContent.title\": {\n    \"message\": \"This page crashed.\",\n    \"description\": \"The title of the fallback"
  },
  {
    "path": "teams.md/i18n/en/docusaurus-plugin-content-docs/current.json",
    "chars": 103,
    "preview": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  }\n}\n"
  },
  {
    "path": "teams.md/i18n/en/docusaurus-plugin-content-docs-csharp/current.json",
    "chars": 103,
    "preview": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  }\n}\n"
  },
  {
    "path": "teams.md/i18n/en/docusaurus-plugin-content-docs-typescript/current.json",
    "chars": 769,
    "preview": "{\n  \"version.label\": {\n    \"message\": \"Next\",\n    \"description\": \"The label for version current\"\n  },\n  \"sidebar.default"
  },
  {
    "path": "teams.md/i18n/en/docusaurus-theme-classic/footer.json",
    "chars": 1005,
    "preview": "{\n  \"link.title.Docs\": {\n    \"message\": \"Docs\",\n    \"description\": \"The title of the footer links column with title=Docs"
  },
  {
    "path": "teams.md/i18n/en/docusaurus-theme-classic/navbar.json",
    "chars": 510,
    "preview": "{\n  \"title\": {\n    \"message\": \"Teams SDK\",\n    \"description\": \"The title in the navbar\"\n  },\n  \"logo.alt\": {\n    \"messag"
  },
  {
    "path": "teams.md/package.json",
    "chars": 1823,
    "preview": "{\n  \"name\": \"teams-md\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"sta"
  },
  {
    "path": "teams.md/scripts/generate-language-docs.ts",
    "chars": 31837,
    "preview": "#!/usr/bin/env node\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as chokidar from 'chokidar';\nimpor"
  },
  {
    "path": "teams.md/scripts/generate-llms-txt.ts",
    "chars": 24635,
    "preview": "#!/usr/bin/env node\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { collectFiles, getHierarchicalFile"
  },
  {
    "path": "teams.md/scripts/lib/content-processor.ts",
    "chars": 17022,
    "preview": "import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { FrontmatterParser } from './frontmatter-parser';\nimpor"
  },
  {
    "path": "teams.md/scripts/lib/file-collector.ts",
    "chars": 10596,
    "preview": "import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { FrontmatterParser } from './frontmatter-parser';\nimpor"
  },
  {
    "path": "teams.md/scripts/lib/frontmatter-parser.ts",
    "chars": 5530,
    "preview": "import * as fs from 'fs';\nimport * as yaml from 'js-yaml';\n\nimport readFileUtf8Normalized from '../../src/utils/readFile"
  },
  {
    "path": "teams.md/sidebars.ts",
    "chars": 169,
    "preview": "import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';\n\nexport default {\n  default: [{ type: 'autogenerate"
  },
  {
    "path": "teams.md/src/components/FileCodeBlock.tsx",
    "chars": 1145,
    "preview": "import { useEffect, useState, PropsWithChildren } from \"react\";\nimport CodeBlock from \"@theme/CodeBlock\";\nimport useBase"
  },
  {
    "path": "teams.md/src/components/LangLink.tsx",
    "chars": 758,
    "preview": "import React, { type PropsWithChildren } from 'react';\nimport Link from '@docusaurus/Link';\nimport { useLanguagePreferen"
  },
  {
    "path": "teams.md/src/components/Language.tsx",
    "chars": 563,
    "preview": "import { PropsWithChildren } from 'react';\nimport { useLocation } from '@docusaurus/router';\nimport { type Language } fr"
  },
  {
    "path": "teams.md/src/components/LanguageBanner.tsx",
    "chars": 2002,
    "preview": "import React, { useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { LANGUAGE_NAMES, typ"
  },
  {
    "path": "teams.md/src/components/LanguageDropdown.tsx",
    "chars": 9930,
    "preview": "import React, { useEffect, useState, useRef } from 'react';\nimport { useLocation } from '@docusaurus/router';\nimport { u"
  },
  {
    "path": "teams.md/src/components/include/essentials/api/csharp.incl.md",
    "chars": 1976,
    "preview": "<!-- api-object-name -->\n\n`app.Api`\n\n<!-- api-table -->\n\n| Area            | Description                                "
  },
  {
    "path": "teams.md/src/components/include/essentials/api/python.incl.md",
    "chars": 1888,
    "preview": "<!-- api-object-name -->\n\n`app.api`\n\n<!-- api-table -->\n\n| Area            | Description                                "
  },
  {
    "path": "teams.md/src/components/include/essentials/api/typescript.incl.md",
    "chars": 1913,
    "preview": "<!-- api-object-name -->\n\n`app.api`\n\n<!-- api-table -->\n\n| Area            | Description                                "
  },
  {
    "path": "teams.md/src/components/include/essentials/app-authentication/csharp.incl.md",
    "chars": 1637,
    "preview": "<!-- configure-application -->\n\n:::note\nThe environment file approach is not yet supported for C#. You need to configure"
  },
  {
    "path": "teams.md/src/components/include/essentials/app-authentication/python.incl.md",
    "chars": 535,
    "preview": "<!-- configure-application -->\n\nYour application should automatically use User Managed Identity authentication when you "
  },
  {
    "path": "teams.md/src/components/include/essentials/app-authentication/typescript.incl.md",
    "chars": 535,
    "preview": "<!-- configure-application -->\n\nYour application should automatically use User Managed Identity authentication when you "
  },
  {
    "path": "teams.md/src/components/include/essentials/csharp.incl.md",
    "chars": 681,
    "preview": "<!-- key-terms -->\n\n- Event: Anything interesting that happens on Teams — or within your application as a result of hand"
  },
  {
    "path": "teams.md/src/components/include/essentials/graph/csharp.incl.md",
    "chars": 1367,
    "preview": "<!-- package-info -->\n\n`Microsoft.Graph` package\n\n<!-- migration-note -->\n\nN/A\n\n<!-- package-overview -->\n\nN/A\n\n<!-- app"
  },
  {
    "path": "teams.md/src/components/include/essentials/graph/python.incl.md",
    "chars": 1233,
    "preview": "<!-- package-info -->\n\n`microsoft-teams-graph` package\n\n<!-- migration-note -->\n\nN/A\n\n<!-- package-overview -->\n\nN/A\n\n<!"
  },
  {
    "path": "teams.md/src/components/include/essentials/graph/typescript.incl.md",
    "chars": 10171,
    "preview": "<!-- package-info -->\n\n`@microsoft/teams.graph`, `@microsoft/teams.graph-endpoints` and `@microsoft/teams.graph-endpoint"
  },
  {
    "path": "teams.md/src/components/include/essentials/on-activity/csharp.incl.md",
    "chars": 1964,
    "preview": "<!-- intro -->\n\nThe Teams SDK exposes a fluent router so you can subscribe to these activities with `app.OnActivity(...)"
  },
  {
    "path": "teams.md/src/components/include/essentials/on-activity/python.incl.md",
    "chars": 1931,
    "preview": "<!-- intro -->\n\nThe Teams SDK exposes a fluent router so you can subscribe to these activities with `@app.event(\"activit"
  },
  {
    "path": "teams.md/src/components/include/essentials/on-activity/typescript.incl.md",
    "chars": 2047,
    "preview": "<!-- intro -->\n\nThe Teams SDK exposes a fluent router so you can subscribe to these activities with `app.on('<route>', …"
  },
  {
    "path": "teams.md/src/components/include/essentials/on-event/csharp.incl.md",
    "chars": 1760,
    "preview": "<!-- mermaid-diagram -->\n\n```mermaid\nflowchart LR\n    Teams[\"Teams\"]:::less-interesting\n    Server[\"App Server\"]:::inter"
  },
  {
    "path": "teams.md/src/components/include/essentials/on-event/python.incl.md",
    "chars": 2126,
    "preview": "<!-- mermaid-diagram -->\n\n```mermaid\nflowchart LR\n    Teams[\"Teams\"]:::less-interesting\n    Server[\"App Server\"]:::inter"
  },
  {
    "path": "teams.md/src/components/include/essentials/on-event/typescript.incl.md",
    "chars": 1944,
    "preview": "<!-- mermaid-diagram -->\n\n```mermaid\nflowchart LR\n    Teams[\"Teams\"]:::less-interesting\n    Server[\"App Server\"]:::inter"
  },
  {
    "path": "teams.md/src/components/include/essentials/python.incl.md",
    "chars": 702,
    "preview": "<!-- key-terms -->\n\n- Event: Anything interesting that happens on Teams — or within your application as a result of hand"
  },
  {
    "path": "teams.md/src/components/include/essentials/sending-messages/csharp.incl.md",
    "chars": 2209,
    "preview": "<!-- basic-message-example -->\n\n```csharp\napp.OnMessage(async (context, cancellationToken) =>\n{\n    await context.Send($"
  },
  {
    "path": "teams.md/src/components/include/essentials/sending-messages/proactive-messaging/csharp.incl.md",
    "chars": 1435,
    "preview": "<!-- conversation-id-field -->\n\n`conversationId`\n\n<!-- install-handler-example -->\n\nimport Tabs from '@theme/Tabs';\nimpo"
  },
  {
    "path": "teams.md/src/components/include/essentials/sending-messages/proactive-messaging/python.incl.md",
    "chars": 1686,
    "preview": "<!-- conversation-id-field -->\n\n`conversation_id`\n\n<!-- install-handler-example -->\n\n```python\nfrom microsoft_teams.api "
  },
  {
    "path": "teams.md/src/components/include/essentials/sending-messages/proactive-messaging/typescript.incl.md",
    "chars": 1701,
    "preview": "<!-- conversation-id-field -->\n\n`conversationId`\n\n<!-- install-handler-example -->\n\n```typescript\nimport { MessageActivi"
  },
  {
    "path": "teams.md/src/components/include/essentials/sending-messages/python.incl.md",
    "chars": 1706,
    "preview": "<!-- basic-message-example -->\n\n```python\n@app.on_message\nasync def handle_message(ctx: ActivityContext[MessageActivity]"
  },
  {
    "path": "teams.md/src/components/include/essentials/sending-messages/typescript.incl.md",
    "chars": 1267,
    "preview": "<!-- basic-message-example -->\n\n```typescript\napp.on('message', async ({ activity, send }) => {\n  await send(`You said: "
  },
  {
    "path": "teams.md/src/components/include/essentials/typescript.incl.md",
    "chars": 671,
    "preview": "<!-- key-terms -->\n\n- Event: Anything interesting that happens on Teams — or within your application as a result of hand"
  },
  {
    "path": "teams.md/src/components/include/getting-started/_LLMs/csharp.incl.md",
    "chars": 629,
    "preview": "<!-- language-name -->\n\nC#\n\n<!-- file-links -->\n\n**Small**: [llms_csharp.txt](https://microsoft.github.io/teams-sdk/llms"
  },
  {
    "path": "teams.md/src/components/include/getting-started/_LLMs/python.incl.md",
    "chars": 641,
    "preview": "<!-- language-name -->\n\nPython\n\n<!-- file-links -->\n\n**Small**: [llms_python.txt](https://microsoft.github.io/teams-sdk/"
  },
  {
    "path": "teams.md/src/components/include/getting-started/_LLMs/typescript.incl.md",
    "chars": 669,
    "preview": "<!-- language-name -->\n\nTypeScript\n\n<!-- file-links -->\n\n**Small**: [llms_typescript.txt](https://microsoft.github.io/te"
  },
  {
    "path": "teams.md/src/components/include/getting-started/code-basics/csharp.incl.md",
    "chars": 1840,
    "preview": "<!-- imports -->\n\nN/A\n\n<!-- project-structure -->\n\n```\nQuote.Agent/\n|── appPackage/       # Teams app package files\n├── "
  },
  {
    "path": "teams.md/src/components/include/getting-started/code-basics/python.incl.md",
    "chars": 1943,
    "preview": "<!-- imports -->\n\nN/A\n\n<!-- project-structure -->\n\n```\nquote-agent/\n|── appPackage/       # Teams app package files\n├── "
  },
  {
    "path": "teams.md/src/components/include/getting-started/code-basics/typescript.incl.md",
    "chars": 1750,
    "preview": "<!-- imports -->\n\nN/A\n\n<!-- project-structure -->\n\n```\nquote-agent/\n|── appPackage/       # Teams app package files\n├── "
  },
  {
    "path": "teams.md/src/components/include/getting-started/csharp.incl.md",
    "chars": 50,
    "preview": "<!-- warning -->\n\nN/A\n\n<!-- language-name -->\n\nC#\n"
  },
  {
    "path": "teams.md/src/components/include/getting-started/python.incl.md",
    "chars": 219,
    "preview": "<!-- warning -->\n\n:::warning\nOur Python SDK is currently in Public Preview. We're going to do our best to not ship break"
  },
  {
    "path": "teams.md/src/components/include/getting-started/quickstart/csharp.incl.md",
    "chars": 1654,
    "preview": "<!-- prerequisites -->\n\n- **.NET** v.8 or higher. Install or upgrade from [dotnet.microsoft.com](https://dotnet.microsof"
  },
  {
    "path": "teams.md/src/components/include/getting-started/quickstart/python.incl.md",
    "chars": 2732,
    "preview": "<!-- prerequisites -->\n\n- **Python** v3.12 or higher. Install or upgrade from [python.org/downloads](https://www.python."
  },
  {
    "path": "teams.md/src/components/include/getting-started/quickstart/typescript.incl.md",
    "chars": 2568,
    "preview": "<!-- prerequisites -->\n\n- **Node.js** v.20 or higher. Install or upgrade from [nodejs.org](https://nodejs.org/).\n\n<!-- c"
  },
  {
    "path": "teams.md/src/components/include/getting-started/running-in-teams/csharp.incl.md",
    "chars": 492,
    "preview": "<!-- terminal-output -->\n\n```sh\n[INFO] Microsoft.Hosting.Lifetime Now listening on: http://localhost:3978\n[WARN] Echo.Mi"
  },
  {
    "path": "teams.md/src/components/include/getting-started/running-in-teams/python.incl.md",
    "chars": 452,
    "preview": "<!-- terminal-output -->\n\n```sh\n[INFO] @teams/app Successfully initialized all plugins\n[INFO] @teams/app.HttpPlugin Star"
  },
  {
    "path": "teams.md/src/components/include/getting-started/running-in-teams/typescript.incl.md",
    "chars": 467,
    "preview": "<!-- terminal-output -->\n\n```sh\n[nodemon] 3.1.9\n[nodemon] to restart at any time, enter `rs`\n[nodemon] watching path(s):"
  },
  {
    "path": "teams.md/src/components/include/getting-started/typescript.incl.md",
    "chars": 58,
    "preview": "<!-- warning -->\n\nN/A\n\n<!-- language-name -->\n\nTypeScript\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/building-adaptive-cards/csharp.incl.md",
    "chars": 6425,
    "preview": "<!-- package-name -->\n\n`Microsoft.Teams.Cards`\n\n<!-- intro-description -->\n\nWith `Microsoft.Teams.Cards` you can build t"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/building-adaptive-cards/python.incl.md",
    "chars": 5101,
    "preview": "<!-- package-name -->\n\n`microsoft-teams-cards`\n\n<!-- intro-description -->\n\nWith `microsoft-teams-cards` you can build t"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/building-adaptive-cards/typescript.incl.md",
    "chars": 4039,
    "preview": "<!-- package-name -->\n\n`@microsoft/teams.cards`\n\n<!-- intro-description -->\n\nWith `@microsoft/teams.cards` you can build"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/csharp.incl.md",
    "chars": 130,
    "preview": "<!-- intro -->\n\nOverview of Adaptive Cards in C# Teams SDK for building rich, interactive user experiences in Teams appl"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/executing-actions/csharp.incl.md",
    "chars": 8434,
    "preview": "<!-- single-action-example -->\n\n```csharp\nusing Microsoft.Teams.Cards;\n\nvar action = new ExecuteAction\n{\n    Title = \"Su"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/executing-actions/python.incl.md",
    "chars": 5246,
    "preview": "<!-- single-action-example -->\n\n```python\nfrom microsoft_teams.cards.core import ExecuteAction\n# ...\n\naction = ExecuteAc"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/executing-actions/typescript.incl.md",
    "chars": 4675,
    "preview": "<!-- single-action-example -->\n\n```typescript\nimport { ExecuteAction } from '@microsoft/teams.cards';\n// ...\n\nnew Execut"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/python.incl.md",
    "chars": 134,
    "preview": "<!-- intro -->\n\nOverview of Adaptive Cards in Python Teams SDK for building rich, interactive user experiences in Teams "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/adaptive-cards/typescript.incl.md",
    "chars": 138,
    "preview": "<!-- intro -->\n\nOverview of Adaptive Cards in TypeScript Teams SDK for building rich, interactive user experiences in Te"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/a2a/a2a-client/python.incl.md",
    "chars": 6305,
    "preview": "<!-- direct-client -->\n\n```python\nimport uuid\nfrom httpx import AsyncClient\nfrom a2a.types import AgentCard, Message, Pa"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/a2a/a2a-client/typescript.incl.md",
    "chars": 4123,
    "preview": "<!-- direct-client -->\n\n```typescript\nimport { A2AClient } from '@a2a-js/sdk/client';\n\n// Create client from agent card "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/a2a/a2a-server/python.incl.md",
    "chars": 2199,
    "preview": "<!-- agent-card -->\n\n`agent_card`\n\n<!-- plugin-example -->\n\n```python\nfrom os import getenv\nfrom a2a.types import AgentC"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/a2a/a2a-server/typescript.incl.md",
    "chars": 1440,
    "preview": "<!-- agent-card -->\n\n`agentCard`\n\n<!-- plugin-example -->\n\n```typescript\nimport { AgentCard } from '@a2a-js/sdk';\nimport"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/a2a/python.incl.md",
    "chars": 224,
    "preview": "<!-- note -->\n\n:::note\nThis package wraps the official [A2A SDK](https://github.com/a2aproject/a2a-python) for both serv"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/a2a/typescript.incl.md",
    "chars": 221,
    "preview": "<!-- note -->\n\n:::note\nThis package wraps the official [A2A SDK](https://github.com/a2aproject/a2a-js) for both server a"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/best-practices/csharp.incl.md",
    "chars": 1301,
    "preview": "<!-- ai-generated-method -->\n\nThis can be done by calling the `.AddAIGenerated()` method on outgoing messages.\n\n<!-- ai-"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/best-practices/python.incl.md",
    "chars": 1419,
    "preview": "<!-- ai-generated-method -->\n\nThis can be done by adding a `addAiGenerated` property to outgoing message.\n\n<!-- ai-gener"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/best-practices/typescript.incl.md",
    "chars": 1281,
    "preview": "<!-- ai-generated-method -->\n\nThis can be done by adding a `addAiGenerated` property to outgoing message.\n\n<!-- ai-gener"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/chat/csharp.incl.md",
    "chars": 3752,
    "preview": "<!-- simple-chat-setup -->\n\nImport the relevant namespaces:\n\n```csharp\n// AI\nusing Microsoft.Teams.AI.Models.OpenAI;\nusi"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/chat/python.incl.md",
    "chars": 2518,
    "preview": "<!-- simple-chat-setup -->\n\nImport the relevant objects:\n\n```python\nfrom microsoft_teams.ai import ChatPrompt\nfrom micro"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/chat/typescript.incl.md",
    "chars": 2460,
    "preview": "<!-- simple-chat-setup -->\n\nImport the relevant objects:\n\n```typescript\nimport { OpenAIChatModel } from '@microsoft/team"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/csharp.incl.md",
    "chars": 44,
    "preview": "<!-- package-name -->\n\n`Microsoft.Teams.AI`\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/function-calling/csharp.incl.md",
    "chars": 13117,
    "preview": "<!-- adding-functions -->\n\nregistering functions with a `ChatPrompt` using the `.Function()` method\n\n<!-- sequence-diagr"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/function-calling/python.incl.md",
    "chars": 5925,
    "preview": "<!-- adding-functions -->\n\nadding a `function` to the `ChatPrompt`\n\n<!-- sequence-diagram -->\n\n```mermaid\nsequenceDiagra"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/function-calling/typescript.incl.md",
    "chars": 6122,
    "preview": "<!-- adding-functions -->\n\nadding a `function` to the `ChatPrompt`\n\n<!-- sequence-diagram -->\n\n```mermaid\nsequenceDiagra"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/keeping-state/csharp.incl.md",
    "chars": 3890,
    "preview": "<!-- state-initialization -->\n\n```csharp\nusing Microsoft.Teams.AI;\nusing Microsoft.Teams.AI.Messages;\nusing Microsoft.Te"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/keeping-state/python.incl.md",
    "chars": 2990,
    "preview": "<!-- state-initialization -->\n\n```python\nfrom microsoft_teams.ai import ChatPrompt, ListMemory, AIModel\nfrom microsoft_t"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/keeping-state/typescript.incl.md",
    "chars": 2222,
    "preview": "<!-- state-initialization -->\n\n```typescript\nimport { ChatPrompt, IChatModel, Message } from '@microsoft/teams.ai';\nimpo"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/mcp/mcp-client/csharp.incl.md",
    "chars": 3274,
    "preview": "<!-- protocol-name -->\n\nSSE protocol\n\n<!-- install -->\n\nInstall it to your application:\n\n```bash\ndotnet add package Micr"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/mcp/mcp-client/python.incl.md",
    "chars": 3423,
    "preview": "<!-- protocol-name -->\n\nSSE protocol\n\n<!-- install -->\n\nInstall it to your application:\n\n```bash\npip install microsoft-t"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/mcp/mcp-client/typescript.incl.md",
    "chars": 2820,
    "preview": "<!-- protocol-name -->\n\nStreamable HTTP protocol\n\n<!-- install -->\n\nInstall it to your application:\n\n```bash\nnpm install"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/mcp/mcp-server/csharp.incl.md",
    "chars": 210,
    "preview": "<!-- intro -->\n\nWIP\n\n<!-- install -->\n\n<!-- configuration -->\n\n<!-- path-note -->\n\n<!-- app-integration -->\n\n<!-- devtoo"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/mcp/mcp-server/python.incl.md",
    "chars": 4072,
    "preview": "<!-- intro -->\n\nYou are able to convert any `App` into an MCP server by using the `McpPlugin` from the `microsoft-teams-"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/mcp/mcp-server/typescript.incl.md",
    "chars": 4241,
    "preview": "<!-- intro -->\n\nYou are able to convert any `App` into an MCP server by using the `McpPlugin`. This plugin adds the nece"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/python.incl.md",
    "chars": 52,
    "preview": "<!-- package-name -->\n\n`microsoft-teams-ai` package\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/setup-and-prereqs/csharp.incl.md",
    "chars": 2301,
    "preview": "<!-- package-install -->\n\n**NuGet Package** - Install the Microsoft Teams SDK:\n\n```bash\ndotnet add package Microsoft.Tea"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/setup-and-prereqs/python.incl.md",
    "chars": 1783,
    "preview": "<!-- package-install -->\n\nN/A\n\n<!-- config-method -->\n\nWe recommend putting it in an .env file at the root level of your"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/setup-and-prereqs/typescript.incl.md",
    "chars": 2335,
    "preview": "<!-- package-install -->\n\nInstall the required AI packages to your application:\n\n```bash\nnpm install @microsoft/teams.ap"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/ai/typescript.incl.md",
    "chars": 53,
    "preview": "<!-- package-name -->\n\n`@microsoft/teams.ai` package\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/csharp.incl.md",
    "chars": 101,
    "preview": "<!-- intro -->\n\nThis documentation covers advanced features and capabilities of the Teams SDK in C#.\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/creating-dialogs/csharp.incl.md",
    "chars": 6910,
    "preview": "<!-- entry-point-intro -->\n\nTo open a dialog, you need to supply a special type of action to the Adaptive Card. The `Tas"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/creating-dialogs/python.incl.md",
    "chars": 5372,
    "preview": "<!-- entry-point-intro -->\n\nTo open a dialog, you need to supply a special type of action as to the Adaptive Card. Once "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/creating-dialogs/typescript.incl.md",
    "chars": 4390,
    "preview": "<!-- entry-point-intro -->\n\nTo open a dialog, you need to supply a special type of action as to the Adaptive Card. Once "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/handling-dialog-submissions/csharp.incl.md",
    "chars": 5448,
    "preview": "<!-- event-intro -->\n\nDialogs have a specific `TaskSubmit` event to handle submissions. When a user submits a form insid"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/handling-dialog-submissions/python.incl.md",
    "chars": 2084,
    "preview": "<!-- event-intro -->\n\nDialogs have a specific `dialog_submit` event to handle submissions. When a user submits a form in"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/handling-dialog-submissions/typescript.incl.md",
    "chars": 1680,
    "preview": "<!-- event-intro -->\n\nDialogs have a specific `dialog.submit` event to handle submissions. When a user submits a form in"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/handling-multi-step-forms/csharp.incl.md",
    "chars": 7216,
    "preview": "<!-- initial-setup -->\n\n## Creating the Initial Dialog\n\nStart off by sending an initial card in the `TaskFetch` event.\n\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/handling-multi-step-forms/python.incl.md",
    "chars": 3690,
    "preview": "<!-- initial-setup -->\n\nStart off by sending an initial card in the `dialog_open` event.\n\n<!-- initial-card -->\n\n```pyth"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/dialogs/handling-multi-step-forms/typescript.incl.md",
    "chars": 2934,
    "preview": "<!-- initial-setup -->\n\nStart off by sending an initial card in the `dialog.open` event.\n\n<!-- initial-card -->\n\n```type"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/feedback/csharp.incl.md",
    "chars": 2728,
    "preview": "<!-- storage -->\n\n```csharp\n// This store would ideally be persisted in a database\npublic static class FeedbackStore\n{\n "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/feedback/python.incl.md",
    "chars": 2820,
    "preview": "<!-- storage -->\n\nOnce you receive a feedback event, you can choose to store it in some persistent storage. You'll need "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/feedback/typescript.incl.md",
    "chars": 2010,
    "preview": "<!-- storage -->\n\n```typescript\nimport { ChatPrompt, IChatModel } from '@microsoft/teams.ai';\nimport { ActivityLike, IMe"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/meeting-events/csharp.incl.md",
    "chars": 3341,
    "preview": "<!-- meeting-start -->\n\n```csharp\nusing Microsoft.Teams.Apps;\nusing Microsoft.Teams.Apps.Activities;\nusing Microsoft.Tea"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/meeting-events/python.incl.md",
    "chars": 3027,
    "preview": "<!-- meeting-start -->\n\n```python\nfrom microsoft_teams.api.activities.event import MeetingStartEventActivity\nfrom micros"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/meeting-events/typescript.incl.md",
    "chars": 2245,
    "preview": "<!-- meeting-start -->\n\n```typescript\nimport { App } from '@microsoft/teams.apps';\nimport { AdaptiveCard, TextBlock, Ope"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/action-commands/csharp.incl.md",
    "chars": 6833,
    "preview": "<!-- handle-submission-intro -->\n\nHandle submission when the `createCard` or `getMessageDetails` actions commands are in"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/action-commands/python.incl.md",
    "chars": 7046,
    "preview": "<!-- handle-submission-intro -->\n\nHandle submission when the `createCard` or `getMessageDetails` actions commands are in"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/action-commands/typescript.incl.md",
    "chars": 4971,
    "preview": "<!-- handle-submission-intro -->\n\nHandle submission when the `createCard` or `getMessageDetails` action commands are inv"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/link-unfurling/csharp.incl.md",
    "chars": 2375,
    "preview": "<!-- handle-link-unfurling-code -->\n\n```csharp\nusing Microsoft.Teams.Api.Activities.Invokes.MessageExtensions;\nusing Mic"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/link-unfurling/python.incl.md",
    "chars": 2490,
    "preview": "<!-- handle-link-unfurling-code -->\n\n```python\nfrom microsoft_teams.api import (\n    AdaptiveCardAttachment,\n    Message"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/link-unfurling/typescript.incl.md",
    "chars": 1494,
    "preview": "<!-- handle-link-unfurling-code -->\n\n```typescript\nimport { cardAttachment } from '@microsoft/teams.api';\nimport { App }"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/search-commands/csharp.incl.md",
    "chars": 4958,
    "preview": "<!-- handle-submission-code -->\n\n```csharp\nusing Microsoft.Teams.Api.Activities.Invokes.MessageExtensions;\nusing Microso"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/search-commands/python.incl.md",
    "chars": 4101,
    "preview": "<!-- handle-submission-code -->\n\n```python\nfrom microsoft_teams.api import AdaptiveCardAttachment, MessageExtensionQuery"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/search-commands/typescript.incl.md",
    "chars": 2757,
    "preview": "<!-- handle-submission-code -->\n\n```typescript\nimport { cardAttachment } from '@microsoft/teams.api';\nimport { App } fro"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/settings/csharp.incl.md",
    "chars": 5300,
    "preview": "<!-- html-code -->\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>Message Extension Settings</title>\n    <link\n    "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/settings/python.incl.md",
    "chars": 3631,
    "preview": "<!-- html-code -->\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>Message Extension Settings</title>\n    <link\n    "
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/message-extensions/settings/typescript.incl.md",
    "chars": 3674,
    "preview": "<!-- html-code -->\n\n```html\n<html>\n  <body>\n    <form>\n      <fieldset>\n        <legend>What programming language do you"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/observability/logging/csharp.incl.md",
    "chars": 461,
    "preview": "<!-- default-logger -->\n\n`ConsoleLogger`\n\n<!-- package-name -->\n\n`Microsoft.Teams.Common`\n\n<!-- custom-logger-example --"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/observability/logging/python.incl.md",
    "chars": 774,
    "preview": "<!-- default-logger -->\n\n`ConsoleLogger`\n\n<!-- package-name -->\n\n`microsoft-teams-common`\n\n<!-- custom-logger-example --"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/observability/logging/typescript.incl.md",
    "chars": 604,
    "preview": "<!-- default-logger -->\n\n`ConsoleLogger`\n\n<!-- package-name -->\n\n`@microsoft/teams.common`\n\n<!-- custom-logger-example -"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/observability/middleware/csharp.incl.md",
    "chars": 371,
    "preview": "<!-- app-use-method -->\n\n`app.Use`\n\n<!-- middleware-example -->\n\n```csharp\napp.Use(async context =>\n{\n    var start = Da"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/observability/middleware/python.incl.md",
    "chars": 259,
    "preview": "<!-- app-use-method -->\n\n`app.use`\n\n<!-- middleware-example -->\n\n```python\n@app.use\nasync def log_activity(ctx: Activity"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/observability/middleware/typescript.incl.md",
    "chars": 227,
    "preview": "<!-- app-use-method -->\n\n`app.use`\n\n<!-- middleware-example -->\n\n```typescript\napp.use(async ({ log, next }) => {\n  cons"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/python.incl.md",
    "chars": 105,
    "preview": "<!-- intro -->\n\nThis documentation covers advanced features and capabilities of the Teams SDK in Python.\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/server/http-server/csharp.incl.md",
    "chars": 90,
    "preview": "<!-- adapter-interface -->\n\nN/A\n\n<!-- self-managed -->\n\nN/A\n\n<!-- custom-adapter -->\n\nN/A\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/server/http-server/python.incl.md",
    "chars": 3102,
    "preview": "<!-- default-framework -->\n\n[FastAPI](https://fastapi.tiangolo.com/)\n\n<!-- adapter-interface -->\n\n```python\nclass HttpSe"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/server/http-server/typescript.incl.md",
    "chars": 2724,
    "preview": "<!-- default-framework -->\n\n[Express](https://expressjs.com/)\n\n<!-- adapter-interface -->\n\n```typescript\ninterface IHttp"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/server/static-pages/csharp.incl.md",
    "chars": 424,
    "preview": "<!-- method-name -->\n\n`app.AddTab()`\n\n<!-- code-example -->\n\n```csharp\napp.AddTab(\"myApp\", \"Web/bin\");\n```\n\n<!-- route-p"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/server/static-pages/python.incl.md",
    "chars": 365,
    "preview": "<!-- method-name -->\n\n`app.tab()`\n\n<!-- code-example -->\n\n```python\napp.tab(\"my_app\", os.path.abspath(\"dist/client\"))\n``"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/server/static-pages/typescript.incl.md",
    "chars": 439,
    "preview": "<!-- method-name -->\n\n`app.tab()`\n\n<!-- code-example -->\n\n```typescript\napp.tab('myApp', path.resolve('dist/client'));\n`"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/tabs/csharp.incl.md",
    "chars": 355,
    "preview": "<!-- overview -->\n\nThis SDK does not offer features for implementing Tab apps in C#. It does however let you host tab ap"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/tabs/functions/csharp.incl.md",
    "chars": 6256,
    "preview": "<!-- overview -->\n\nAgents may want to expose REST APIs that client applications can call. This SDK makes it easy to impl"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/tabs/functions/typescript.incl.md",
    "chars": 7040,
    "preview": "<!-- overview -->\n\nAgents may want to expose REST APIs that client applications can call. This SDK makes it easy to impl"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/tabs/typescript.incl.md",
    "chars": 1229,
    "preview": "<!-- overview -->\n\nTab apps will often need to interact with remote services. They may need to fetch data from [Microsof"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/typescript.incl.md",
    "chars": 109,
    "preview": "<!-- intro -->\n\nThis documentation covers advanced features and capabilities of the Teams SDK in TypeScript.\n"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/user-authentication/csharp.incl.md",
    "chars": 2496,
    "preview": "<!-- create-project -->\n\nUse your terminal to run the following command:\n\n```sh\nnpx @microsoft/teams.cli@latest new csha"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/user-authentication/python.incl.md",
    "chars": 5074,
    "preview": "<!-- create-project -->\n\nUse your terminal to run the following command:\n\n```sh\nnpx @microsoft/teams.cli@latest new pyth"
  },
  {
    "path": "teams.md/src/components/include/in-depth-guides/user-authentication/typescript.incl.md",
    "chars": 4186,
    "preview": "<!-- create-project -->\n\nUse your terminal to run the following command:\n\n```sh\nnpx @microsoft/teams.cli@latest new type"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/integration/csharp.incl.md",
    "chars": 2497,
    "preview": "<!-- example -->\n\n<Tabs>\n  <TabItem value=\"Program.cs\" default>\n    ```csharp\n\n    using Microsoft.Bot.Builder.Integrati"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/integration/python.incl.md",
    "chars": 2081,
    "preview": "<!-- example -->\n\n<Tabs>\n  <TabItem value=\"app.py\" default>\n    ```python\n    import asyncio\n    from adapter import ada"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/integration/typescript.incl.md",
    "chars": 1746,
    "preview": "<!-- example -->\n\n<Tabs>\n  <TabItem value=\"index.ts\" default>\n    ```typescript\n    import { App } from '@microsoft/team"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/proactive-activities/csharp.incl.md",
    "chars": 2256,
    "preview": "<!-- example -->\n\n<Tabs groupId=\"proactive-activities\">\n  <TabItem value=\"Diff\" default>\n    ```csharp\n    // highlight-"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/proactive-activities/python.incl.md",
    "chars": 2429,
    "preview": "<!-- example -->\n\n<Tabs groupId=\"proactive-activities\">\n  <TabItem value=\"Diff\" default>\n    ```python\n    # highlight-e"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/proactive-activities/typescript.incl.md",
    "chars": 2424,
    "preview": "<!-- example -->\n\n<Tabs groupId=\"proactive-activities\">\n  <TabItem value=\"Diff\" default>\n    ```typescript\n    // highli"
  },
  {
    "path": "teams.md/src/components/include/migrations/botbuilder/sending-activities/csharp.incl.md",
    "chars": 9622,
    "preview": "<!-- examples -->\n\n<Tabs groupId=\"sending-activities\">\n  <TabItem value=\"Diff\" default>\n    ```csharp\n    // highlight-e"
  }
]

// ... and 118 more files (download for full content)

About this extraction

This page contains the full source code of the microsoft/teams-ai GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 318 files (858.9 KB), approximately 207.5k tokens, and a symbol index with 116 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!