[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69B7PC8ECMHNK0KJDH5D1BK":3,"skill-same:01M69B7PC8ECMHNK0KJDH5D1BK":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":31,"linkOnly":32,"markdownContent":33,"markdownBody":34,"frontMatter":35,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":41,"ownerHtmlUrl":42,"ownerBlogUrl":43,"ownerDescription":44,"updatedAt":45,"install":46,"resources":59},"01M69B7PC8ECMHNK0KJDH5D1BK","agents-sdk-typescript",null,"Use when any code imports @microsoft\u002Fagents-hosting, @microsoft\u002Fagents-hosting-express, or related Agents SDK packages, or when the user is building, configuring, or asking questions about a Microsoft 365 Agents SDK agent in TypeScript. Trigger on questions about environment variables, connection configuration, AgentApplication patterns, OAuth sign-in flows, storage backends, cards, streaming, or local testing with the Agents Playground — even if no code exists yet and the user is planning or asking how to get started.","microsoft\u002FAgents","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69B7CR81D1HSNV69XDT8KAR",1106,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-js\u002Fskills\u002Fagents-sdk-typescript\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,9,30],"typescript","agents sdk","sdk","agents sdk typescript","testing","storage","packages","2026-11-10 10:12:30",false,"---\nname: agents-sdk-typescript\ndescription: >\n  Use when any code imports @microsoft\u002Fagents-hosting, @microsoft\u002Fagents-hosting-express,\n  or related Agents SDK packages, or when the user is building, configuring, or\n  asking questions about a Microsoft 365 Agents SDK agent in TypeScript. Trigger\n  on questions about environment variables, connection configuration,\n  AgentApplication patterns, OAuth sign-in flows, storage backends, cards,\n  streaming, or local testing with the Agents Playground — even if no code exists\n  yet and the user is planning or asking how to get started.\n---\n\n## Overview\n\nThe Microsoft 365 Agents SDK builds multichannel agents for Teams, Copilot Studio, and web chat.\n\n| Package | Purpose |\n|---|---|\n| `@microsoft\u002Fagents-hosting` | Core: AgentApplication, CloudAdapter, TurnContext, TurnState, storage |\n| `@microsoft\u002Fagents-hosting-express` | `startServer()` convenience wrapper |\n| `@microsoft\u002Fagents-hosting-storage-blob` | Azure Blob Storage backend |\n| `@microsoft\u002Fagents-hosting-storage-cosmos` | CosmosDB backend |\n| `@microsoft\u002Fagents-hosting-dialogs` | Dialog system |\n\nRequires Node 18+. Use `node --env-file .env` (Node 20+) to load environment variables.\n\n## Azure Resources Required\n\n**Microsoft Entra App Registration**\n- `clientId` — Application (client) ID\n- `clientSecret` — Certificates & secrets\n- `tenantId` — Directory (tenant) ID\n\n**Azure Bot Resource**\n- Messaging endpoint: `https:\u002F\u002F\u003Cyour-host>\u002Fapi\u002Fmessages`\n- Microsoft App ID must match `clientId`\n\nLocal dev: Use Bot Framework Emulator. No Azure Bot needed until deployment. Leave `clientId` blank to skip auth validation.\n\n## Environment Variables\n\n### Modern format (recommended)\n\nUses `connections__` and `connectionsMap__` prefixes. Double underscores (`__`) separate path segments; `.settings.` is stripped automatically.\n\n**Single connection (most common):**\n```\nconnections__serviceConnection__settings__clientId=\u003Cyour-app-id>\nconnections__serviceConnection__settings__clientSecret=\u003Cyour-secret>\nconnections__serviceConnection__settings__tenantId=\u003Cyour-tenant-id>\nconnectionsMap__0__connection=serviceConnection\nconnectionsMap__0__serviceUrl=*\n```\n\n**How `connectionsMap` works:**\nEach entry maps a `serviceUrl` pattern to a named connection. The first matching entry wins.\n- `serviceUrl=*` — matches any service URL (use as the default\u002Ffallback)\n- `serviceUrl` is treated as a regex for all other values\n\n`connectionsMap` can be omitted when there is only one connection — the SDK defaults it to `serviceUrl=*`.\n\n**Multiple connections** (e.g. different identities for different channels):\n```\nconnections__mainConn__settings__clientId=\u003Capp-id-1>\nconnections__mainConn__settings__clientSecret=\u003Csecret-1>\nconnections__mainConn__settings__tenantId=\u003Ctenant-id>\n\nconnections__teamsConn__settings__clientId=\u003Capp-id-2>\nconnections__teamsConn__settings__clientSecret=\u003Csecret-2>\nconnections__teamsConn__settings__tenantId=\u003Ctenant-id>\n\nconnectionsMap__0__connection=teamsConn\nconnectionsMap__0__serviceUrl=https:\u002F\u002Fsmba.trafficmanager.net\u002F.*\nconnectionsMap__1__connection=mainConn\nconnectionsMap__1__serviceUrl=*\n```\n\nOptional `audience` field on a map entry restricts matching to activities whose JWT `aud` claim equals that value:\n```\nconnectionsMap__0__connection=teamsConn\nconnectionsMap__0__serviceUrl=*\nconnectionsMap__0__audience=\u003Cteams-app-id>\n```\n\n**Available connection settings fields:**\n`clientId`, `clientSecret`, `tenantId`, `authority`, `certPemFile`, `certKeyFile`, `sendX5C`, `connectionName`, `scope`\n\n### Legacy format — backwards compatibility only\n\n> **Never use the legacy format for new agents.** It exists solely for backwards compatibility with older BotFramework-based bots. Always use the modern `connections__` format above.\n\n```\nclientId=\u003Cyour-app-id>\nclientSecret=\u003Cyour-secret>\ntenantId=\u003Cyour-tenant-id>\n```\n\nBoth `startServer()` and `loadAuthConfigFromEnv()` auto-detect the format. Leave `clientId` blank locally to skip auth.\n\n### OAuth authorization handler variables\n\nThese control the user sign-in flow configured via `authorization: { [id]: { ... } }`. The `id` is the key used in the authorization options (e.g. `graph`).\n\n#### Modern format (recommended)\n\nUses the prefix `AgentApplication__UserAuthorization__Handlers__\u003Cid>__Settings__\u003Cproperty>`. Case-insensitive.\n\n**AzureBot handler** (default — user OAuth flow via Azure Bot Service):\n```\nAgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName=GraphOAuthConnection\nAgentApplication__UserAuthorization__Handlers__graph__Settings__title=Sign in with Microsoft\nAgentApplication__UserAuthorization__Handlers__graph__Settings__text=Please sign in to continue\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMax=3\nAgentApplication__UserAuthorization__Handlers__graph__Settings__enableSso=false\n\n# OBO (on-behalf-of) — auto-exchange on routes using exchangeToken()\nAgentApplication__UserAuthorization__Handlers__graph__Settings__oboConnectionName=OBOConnection\nAgentApplication__UserAuthorization__Handlers__graph__Settings__oboScopes=https:\u002F\u002Fgraph.microsoft.com\u002F.default,Mail.Read\n\n# Custom error messages\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMessage=That code was invalid, please try again.\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMessageFormat=Please enter the 6-digit code from the sign-in card.\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMaxExceededMessage=Too many failed attempts. Please try again later.\n```\n\n**AgenticUserAuthorization handler** (agent-to-agent, no user prompt):\n```\nAgentApplication__UserAuthorization__Handlers__myHandler__Settings__type=AgenticUserAuthorization\nAgentApplication__UserAuthorization__Handlers__myHandler__Settings__scopes=https:\u002F\u002Fgraph.microsoft.com\u002F.default\nAgentApplication__UserAuthorization__Handlers__myHandler__Settings__altBlueprintConnectionName=altConn\n```\n\n#### Legacy format (deprecated)\n\n> **Do not use the legacy format for new agents.** It exists solely for backwards compatibility. The SDK emits deprecation warnings when legacy variables are detected.\n\n| Legacy variable | Modern equivalent |\n|---|---|\n| `graph_connectionName` | `...Handlers__graph__Settings__azureBotOAuthConnectionName` |\n| `graph_connectionTitle` | `...Handlers__graph__Settings__title` |\n| `graph_connectionText` | `...Handlers__graph__Settings__text` |\n| `graph_maxAttempts` | `...Handlers__graph__Settings__invalidSignInRetryMax` |\n| `graph_enableSso` | `...Handlers__graph__Settings__enableSso` |\n| `graph_obo_connection` | `...Handlers__graph__Settings__oboConnectionName` |\n| `graph_obo_scopes` | `...Handlers__graph__Settings__oboScopes` |\n| `graph_messages_invalidCode` | `...Handlers__graph__Settings__invalidSignInRetryMessage` |\n| `graph_messages_invalidCodeFormat` | `...Handlers__graph__Settings__invalidSignInRetryMessageFormat` |\n| `graph_messages_maxAttemptsExceeded` | `...Handlers__graph__Settings__invalidSignInRetryMaxExceededMessage` |\n| `myHandler_type=agentic` | `...Handlers__myHandler__Settings__type=AgenticUserAuthorization` |\n| `myHandler_scopes` | `...Handlers__myHandler__Settings__scopes` |\n| `myHandler_altBlueprintConnectionName` | `...Handlers__myHandler__Settings__altBlueprintConnectionName` |\n\nPriority when both formats are present: runtime options (code) > modern env vars > legacy env vars.\n\n## Quick Start\n\n```typescript\nimport { startServer } from '@microsoft\u002Fagents-hosting-express'\nimport { AgentApplication, MemoryStorage, TurnContext, TurnState } from '@microsoft\u002Fagents-hosting'\n\nclass MyAgent extends AgentApplication\u003CTurnState> {\n  constructor() {\n    super({ storage: new MemoryStorage() })\n\n    this.onConversationUpdate('membersAdded', async (ctx: TurnContext) => {\n      await ctx.sendActivity('Hello! Send me a message.')\n    })\n\n    this.onActivity('message', async (ctx: TurnContext, state: TurnState) => {\n      let counter: number = state.getValue('conversation.counter') || 0\n      await ctx.sendActivity(`[${counter++}] You said: ${ctx.activity.text}`)\n      state.setValue('conversation.counter', counter)\n    })\n  }\n}\n\nstartServer(new MyAgent())\n```\n\nRun: `node --env-file .env dist\u002Findex.js`\n\n## Server Setup\n\n### Option A: startServer() (preferred)\n\n`startServer(agent)` creates an Express app with:\n- `express.json()` + `authorizeJWT()` middleware\n- `POST \u002Fapi\u002Fmessages` route\n- Listens on `PORT` env var (default 3978)\n- **Returns the Express instance** — add extra routes to the return value\n\n```typescript\nimport { startServer } from '@microsoft\u002Fagents-hosting-express'\n\nconst server = startServer(agent)\nserver.get('\u002Fhealth', (_req, res) => res.json({ ok: true }))\n```\n\n### Option B: Manual Express\n\n```typescript\nimport express, { Response } from 'express'\nimport { Request, CloudAdapter, authorizeJWT, loadAuthConfigFromEnv } from '@microsoft\u002Fagents-hosting'\n\nconst authConfig = loadAuthConfigFromEnv()\nconst adapter = new CloudAdapter(authConfig)\nconst app = express()\n\napp.use(express.json())\napp.use(authorizeJWT(authConfig))\n\napp.post('\u002Fapi\u002Fmessages', async (req: Request, res: Response) => {\n  await adapter.process(req, res, async (context) => await agent.run(context))\n})\n\napp.listen(process.env.PORT || 3978)\n```\n\n### Proactive Messaging\n\nSave a reference during a turn, then use `adapter.continueConversation` from any route. `req.user` comes from `authorizeJWT` middleware.\n\n```typescript\nimport { ConversationReference } from '@microsoft\u002Fagents-activity'\n\n\u002F\u002F During a turn — save the reference\nconst ref = ctx.activity.getConversationReference()\nconversationReferences[ref.conversation.id] = ref\n\n\u002F\u002F In a proactive route\napp.get('\u002Fapi\u002Fnotify', async (req, res) => {\n  for (const ref of Object.values(conversationReferences)) {\n    await adapter.continueConversation(req.user!, ref, async (ctx) => {\n      await ctx.sendActivity('Proactive message')\n    })\n  }\n  res.json({ ok: true })\n})\n```\n\n## Validating Your Configuration\n\n### 1. Validate bot credentials (clientId \u002F clientSecret \u002F tenantId)\n\nThis tests that your Entra app registration credentials are correct and can authenticate with the Bot Framework. A successful response includes `access_token`; an error response includes `error` and `error_description`.\n\n```bash\ncurl -s -X POST \\\n  \"https:\u002F\u002Flogin.microsoftonline.com\u002F$tenantId\u002Foauth2\u002Fv2.0\u002Ftoken\" \\\n  -d \"grant_type=client_credentials\\\n&client_id=$clientId\\\n&client_secret=$clientSecret\\\n&scope=https:\u002F\u002Fapi.botframework.com\u002F.default\" \\\n  | jq '{token_type, expires_in, error, error_description}'\n```\n\nCommon errors:\n- `AADSTS700016` — `clientId` not found in tenant (wrong ID or wrong tenant)\n- `AADSTS7000215` — invalid `clientSecret` (expired or incorrect)\n- `AADSTS90002` — `tenantId` not found\n\n### 2. Validate the agent is running and reachable\n\n```bash\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n  -X POST http:\u002F\u002Flocalhost:3978\u002Fapi\u002Fmessages \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{}'\n```\n\n- `401` — agent is running; JWT auth rejected the empty request (expected — means auth is working)\n- `000` or connection refused — agent is not running or wrong port\n- `200` — agent is running with auth disabled (local dev with blank `clientId`)\n\n### 3. Validate an OAuth connection name\n\nOAuth connection names (set via `AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName`) can only be tested end-to-end through a real sign-in flow. Use the Azure portal:\n\n**Azure Portal → Your Bot Resource → Settings → OAuth Connection Settings → [your connection] → Test Connection**\n\nThis confirms the connection name matches, the OAuth app has the right scopes, and the redirect URI is configured correctly.\n\n## Local Testing with Agents Playground\n\nThe Agents Playground lets you test your agent locally without deploying to Azure or configuring a Bot resource. It acts as a mock connector service and channel client.\n\n**Install:**\n```bash\nnpm install -g agentsplayground\n```\n\n### Recommended package.json scripts\n\nInclude these scripts when creating a new agent's `package.json`. The `test` script starts the agent and playground together in parallel — no separate terminals needed:\n\n```json\n\"scripts\": {\n  \"prebuild\": \"npm ci\",\n  \"build\": \"tsc --build\",\n  \"prestart\": \"npm run build\",\n  \"prestart:anon\": \"npm run build\",\n  \"start:anon\": \"node .\u002Fdist\u002Findex.js\",\n  \"start\": \"node --env-file .env .\u002Fdist\u002Findex.js\",\n  \"test-tool\": \"agentsplayground -c emulator\",\n  \"test\": \"npm-run-all -p -r start:anon test-tool\"\n}\n```\n\n- `npm start` — builds and runs with `.env` credentials\n- `npm test` — builds, starts the agent without auth (`start:anon`), and launches the playground in parallel. Use this for quick local dev without needing an `.env` file.\n- `-c emulator` — uses the emulator channel (no auth required). Change to `msteams`, `webchat`, etc. as needed.\n- Requires `npm-run-all` as a dev dependency: `npm install -D npm-run-all`\n\n**With authentication** (for testing OAuth\u002Fsign-in flows):\n```bash\nagentsplayground -c msteams \\\n  --client-id \u003Cyour-app-id> \\\n  --client-secret \u003Cyour-secret> \\\n  --tenant-id \u003Cyour-tenant-id>\n```\n\n**Channel options** (`-c`): `msteams`, `webchat`, `directline`, `emulator`, `agents`\n\n## AgentApplication Patterns\n\n**Routing**\n```typescript\nthis.onMessage('\u002Fcmd', handler)              \u002F\u002F exact command\nthis.onActivity('message', handler)          \u002F\u002F all messages\nthis.onConversationUpdate('membersAdded', handler)\nthis.onActivity('invoke', handler)\nthis.onActivity('message', fallback, [], RouteRank.Last) \u002F\u002F fallback\n```\n\n**TurnState** — dot-notation keys auto-scoped to conversation\u002Fuser\u002Ftemp:\n```typescript\nconst count = state.getValue('conversation.counter') || 0\nstate.setValue('conversation.counter', count + 1)\nstate.deleteValue('conversation.counter')\n```\n\n**Storage backends**\n\n| Backend | Use case |\n|---|---|\n| `MemoryStorage` | Local dev only — not persistent |\n| `BlobsStorage` | Azure Blob — production |\n| `CosmosDbPartitionedStorage` | CosmosDB — production |\n\n## Authorization (User Token Flow)\n\n```typescript\nclass MyAgent extends AgentApplication\u003CTurnState> {\n  constructor() {\n    super({\n      storage: new MemoryStorage(),\n      authorization: {\n        graph: {\n          name: 'GraphOAuthConnection', \u002F\u002F OAuth connection name in Azure Bot resource\n          title: 'Sign in with Microsoft',\n          text: 'Please sign in to continue',\n        }\n      }\n    })\n\n    this.onSignInSuccess(async (ctx, state) => {\n      const { token } = await this.authorization.getToken(ctx, 'graph')\n      \u002F\u002F use token to call external APIs\n      await ctx.sendActivity('Signed in!')\n    })\n\n    this.onSignInFailure(async (ctx, state, authId, err) => {\n      await ctx.sendActivity(`Sign-in failed: ${err}`)\n    })\n\n    \u002F\u002F Protect a route — SDK sends the OAuth card automatically if not signed in\n    this.onActivity('message', async (ctx, state) => {\n      const { token } = await this.authorization.getToken(ctx, 'graph')\n      \u002F\u002F token is guaranteed here — route won't run until user is signed in\n    }, ['graph'])\n\n    \u002F\u002F Sign out from all providers\n    this.onMessage('\u002Flogout', async (ctx, state) => {\n      await this.authorization.signOut(ctx, state)\n      await ctx.sendActivity('Signed out.')\n    })\n  }\n}\n```\n\n`name` can also be provided via environment variable `AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName` (where `graph` is the handler key) and omitted from code.\n\n**OBO (on-behalf-of) — exchange user token for a downstream service token:**\n```typescript\nconst { token } = await this.authorization.exchangeToken(ctx, 'graph', {\n  scopes: ['https:\u002F\u002Fgraph.microsoft.com\u002F.default']\n})\n\u002F\u002F use token to call Graph or other downstream APIs\n```\n\n**Agentic auth** (agent-to-agent, no user prompt):\n```typescript\nauthorization: { agentic: { type: 'AgenticUserAuthorization' } }\n\u002F\u002F env: AgentApplication__UserAuthorization__Handlers__agentic__Settings__type=AgenticUserAuthorization\n\u002F\u002F env: AgentApplication__UserAuthorization__Handlers__agentic__Settings__scopes=https:\u002F\u002Fgraph.microsoft.com\u002F.default\n```\n\n## Cards\n\nRead [references\u002Fcards.md](references\u002Fcards.md) when working with Adaptive Cards, Hero Cards, Thumbnail Cards, or other card types.\n\n## Streaming\n\nRead [references\u002Fstreaming.md](references\u002Fstreaming.md) when implementing streaming responses.\n\n## OpenTelemetry \u002F Observability\n\nUse the `agents-sdk-typescript-otel` skill for OpenTelemetry initialization, SDK\ntraces and metrics, OTLP exporters, structured logs, safe custom\ninstrumentation, span-category filtering, Azure Monitor, validation, and the\nlocal Aspire Dashboard.\n\n## Common Mistakes\n\n**1. Wrong field name on ConversationReference**\n\n```typescript\n\u002F\u002F WRONG\nconst ref: ConversationReference = { bot: { id: appId } }\n\n\u002F\u002F CORRECT\nconst ref: ConversationReference = { agent: { id: appId } }\n```\n\n**2. JwtPayload.aud is string | string[]**\n\n```typescript\n\u002F\u002F WRONG\nconst appId = payload.aud\n\n\u002F\u002F CORRECT\nconst appId = Array.isArray(payload.aud) ? payload.aud[0] : payload.aud\n```\n\n**3. Adapter callbacks swallow exceptions**\n\n```typescript\n\u002F\u002F WRONG — error is lost\nawait adapter.continueConversation(identity, ref, async (ctx) => {\n  throw new Error('something failed') \u002F\u002F swallowed\n})\n\n\u002F\u002F CORRECT — capture and rethrow\nlet capturedError: Error | undefined\nawait adapter.continueConversation(identity, ref, async (ctx) => {\n  try {\n    await doWork(ctx)\n  } catch (err) {\n    capturedError = err as Error\n  }\n})\nif (capturedError) throw capturedError\n```\n\n**4. startServer() returns Express — add routes to the return value**\n\n```typescript\n\u002F\u002F WRONG — routes never registered\nconst app = express()\nstartServer(agent)\napp.get('\u002Fhealth', handler)\n\n\u002F\u002F CORRECT\nconst server = startServer(agent)\nserver.get('\u002Fhealth', handler)\n```\n\n### Wrong method names — `activity()` and `message()` don't exist\n\n`AgentApplication` uses `on`-prefixed method names. Common wrong guesses:\n\n```typescript\n\u002F\u002F ❌ wrong — these methods don't exist\napp.activity('message', handler)\napp.message(handler)\n\n\u002F\u002F ✅ correct\napp.onActivity('message', handler)\napp.onMessage('\u002Fhelp', handler)\napp.onConversationUpdate('membersAdded', handler)\n```\n\n## Contributing\n\nIf you hit a problem this skill couldn't solve, found a workaround, or noticed something wrong or outdated, that's valuable — please help improve this skill for everyone.\n\nDraft a suggested issue title and body based on the conversation, then ask the user to open it at: https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fagents\u002Fissues\u002Fnew\n\nA good issue includes:\n- What the user was trying to do\n- What went wrong (errors, unexpected behavior)\n- What worked — including any workaround found during this conversation\n- Relevant code or config snippets\n","## Overview\n\nThe Microsoft 365 Agents SDK builds multichannel agents for Teams, Copilot Studio, and web chat.\n\n| Package | Purpose |\n|---|---|\n| `@microsoft\u002Fagents-hosting` | Core: AgentApplication, CloudAdapter, TurnContext, TurnState, storage |\n| `@microsoft\u002Fagents-hosting-express` | `startServer()` convenience wrapper |\n| `@microsoft\u002Fagents-hosting-storage-blob` | Azure Blob Storage backend |\n| `@microsoft\u002Fagents-hosting-storage-cosmos` | CosmosDB backend |\n| `@microsoft\u002Fagents-hosting-dialogs` | Dialog system |\n\nRequires Node 18+. Use `node --env-file .env` (Node 20+) to load environment variables.\n\n## Azure Resources Required\n\n**Microsoft Entra App Registration**\n- `clientId` — Application (client) ID\n- `clientSecret` — Certificates & secrets\n- `tenantId` — Directory (tenant) ID\n\n**Azure Bot Resource**\n- Messaging endpoint: `https:\u002F\u002F\u003Cyour-host>\u002Fapi\u002Fmessages`\n- Microsoft App ID must match `clientId`\n\nLocal dev: Use Bot Framework Emulator. No Azure Bot needed until deployment. Leave `clientId` blank to skip auth validation.\n\n## Environment Variables\n\n### Modern format (recommended)\n\nUses `connections__` and `connectionsMap__` prefixes. Double underscores (`__`) separate path segments; `.settings.` is stripped automatically.\n\n**Single connection (most common):**\n```\nconnections__serviceConnection__settings__clientId=\u003Cyour-app-id>\nconnections__serviceConnection__settings__clientSecret=\u003Cyour-secret>\nconnections__serviceConnection__settings__tenantId=\u003Cyour-tenant-id>\nconnectionsMap__0__connection=serviceConnection\nconnectionsMap__0__serviceUrl=*\n```\n\n**How `connectionsMap` works:**\nEach entry maps a `serviceUrl` pattern to a named connection. The first matching entry wins.\n- `serviceUrl=*` — matches any service URL (use as the default\u002Ffallback)\n- `serviceUrl` is treated as a regex for all other values\n\n`connectionsMap` can be omitted when there is only one connection — the SDK defaults it to `serviceUrl=*`.\n\n**Multiple connections** (e.g. different identities for different channels):\n```\nconnections__mainConn__settings__clientId=\u003Capp-id-1>\nconnections__mainConn__settings__clientSecret=\u003Csecret-1>\nconnections__mainConn__settings__tenantId=\u003Ctenant-id>\n\nconnections__teamsConn__settings__clientId=\u003Capp-id-2>\nconnections__teamsConn__settings__clientSecret=\u003Csecret-2>\nconnections__teamsConn__settings__tenantId=\u003Ctenant-id>\n\nconnectionsMap__0__connection=teamsConn\nconnectionsMap__0__serviceUrl=https:\u002F\u002Fsmba.trafficmanager.net\u002F.*\nconnectionsMap__1__connection=mainConn\nconnectionsMap__1__serviceUrl=*\n```\n\nOptional `audience` field on a map entry restricts matching to activities whose JWT `aud` claim equals that value:\n```\nconnectionsMap__0__connection=teamsConn\nconnectionsMap__0__serviceUrl=*\nconnectionsMap__0__audience=\u003Cteams-app-id>\n```\n\n**Available connection settings fields:**\n`clientId`, `clientSecret`, `tenantId`, `authority`, `certPemFile`, `certKeyFile`, `sendX5C`, `connectionName`, `scope`\n\n### Legacy format — backwards compatibility only\n\n> **Never use the legacy format for new agents.** It exists solely for backwards compatibility with older BotFramework-based bots. Always use the modern `connections__` format above.\n\n```\nclientId=\u003Cyour-app-id>\nclientSecret=\u003Cyour-secret>\ntenantId=\u003Cyour-tenant-id>\n```\n\nBoth `startServer()` and `loadAuthConfigFromEnv()` auto-detect the format. Leave `clientId` blank locally to skip auth.\n\n### OAuth authorization handler variables\n\nThese control the user sign-in flow configured via `authorization: { [id]: { ... } }`. The `id` is the key used in the authorization options (e.g. `graph`).\n\n#### Modern format (recommended)\n\nUses the prefix `AgentApplication__UserAuthorization__Handlers__\u003Cid>__Settings__\u003Cproperty>`. Case-insensitive.\n\n**AzureBot handler** (default — user OAuth flow via Azure Bot Service):\n```\nAgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName=GraphOAuthConnection\nAgentApplication__UserAuthorization__Handlers__graph__Settings__title=Sign in with Microsoft\nAgentApplication__UserAuthorization__Handlers__graph__Settings__text=Please sign in to continue\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMax=3\nAgentApplication__UserAuthorization__Handlers__graph__Settings__enableSso=false\n\n# OBO (on-behalf-of) — auto-exchange on routes using exchangeToken()\nAgentApplication__UserAuthorization__Handlers__graph__Settings__oboConnectionName=OBOConnection\nAgentApplication__UserAuthorization__Handlers__graph__Settings__oboScopes=https:\u002F\u002Fgraph.microsoft.com\u002F.default,Mail.Read\n\n# Custom error messages\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMessage=That code was invalid, please try again.\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMessageFormat=Please enter the 6-digit code from the sign-in card.\nAgentApplication__UserAuthorization__Handlers__graph__Settings__invalidSignInRetryMaxExceededMessage=Too many failed attempts. Please try again later.\n```\n\n**AgenticUserAuthorization handler** (agent-to-agent, no user prompt):\n```\nAgentApplication__UserAuthorization__Handlers__myHandler__Settings__type=AgenticUserAuthorization\nAgentApplication__UserAuthorization__Handlers__myHandler__Settings__scopes=https:\u002F\u002Fgraph.microsoft.com\u002F.default\nAgentApplication__UserAuthorization__Handlers__myHandler__Settings__altBlueprintConnectionName=altConn\n```\n\n#### Legacy format (deprecated)\n\n> **Do not use the legacy format for new agents.** It exists solely for backwards compatibility. The SDK emits deprecation warnings when legacy variables are detected.\n\n| Legacy variable | Modern equivalent |\n|---|---|\n| `graph_connectionName` | `...Handlers__graph__Settings__azureBotOAuthConnectionName` |\n| `graph_connectionTitle` | `...Handlers__graph__Settings__title` |\n| `graph_connectionText` | `...Handlers__graph__Settings__text` |\n| `graph_maxAttempts` | `...Handlers__graph__Settings__invalidSignInRetryMax` |\n| `graph_enableSso` | `...Handlers__graph__Settings__enableSso` |\n| `graph_obo_connection` | `...Handlers__graph__Settings__oboConnectionName` |\n| `graph_obo_scopes` | `...Handlers__graph__Settings__oboScopes` |\n| `graph_messages_invalidCode` | `...Handlers__graph__Settings__invalidSignInRetryMessage` |\n| `graph_messages_invalidCodeFormat` | `...Handlers__graph__Settings__invalidSignInRetryMessageFormat` |\n| `graph_messages_maxAttemptsExceeded` | `...Handlers__graph__Settings__invalidSignInRetryMaxExceededMessage` |\n| `myHandler_type=agentic` | `...Handlers__myHandler__Settings__type=AgenticUserAuthorization` |\n| `myHandler_scopes` | `...Handlers__myHandler__Settings__scopes` |\n| `myHandler_altBlueprintConnectionName` | `...Handlers__myHandler__Settings__altBlueprintConnectionName` |\n\nPriority when both formats are present: runtime options (code) > modern env vars > legacy env vars.\n\n## Quick Start\n\n```typescript\nimport { startServer } from '@microsoft\u002Fagents-hosting-express'\nimport { AgentApplication, MemoryStorage, TurnContext, TurnState } from '@microsoft\u002Fagents-hosting'\n\nclass MyAgent extends AgentApplication\u003CTurnState> {\n  constructor() {\n    super({ storage: new MemoryStorage() })\n\n    this.onConversationUpdate('membersAdded', async (ctx: TurnContext) => {\n      await ctx.sendActivity('Hello! Send me a message.')\n    })\n\n    this.onActivity('message', async (ctx: TurnContext, state: TurnState) => {\n      let counter: number = state.getValue('conversation.counter') || 0\n      await ctx.sendActivity(`[${counter++}] You said: ${ctx.activity.text}`)\n      state.setValue('conversation.counter', counter)\n    })\n  }\n}\n\nstartServer(new MyAgent())\n```\n\nRun: `node --env-file .env dist\u002Findex.js`\n\n## Server Setup\n\n### Option A: startServer() (preferred)\n\n`startServer(agent)` creates an Express app with:\n- `express.json()` + `authorizeJWT()` middleware\n- `POST \u002Fapi\u002Fmessages` route\n- Listens on `PORT` env var (default 3978)\n- **Returns the Express instance** — add extra routes to the return value\n\n```typescript\nimport { startServer } from '@microsoft\u002Fagents-hosting-express'\n\nconst server = startServer(agent)\nserver.get('\u002Fhealth', (_req, res) => res.json({ ok: true }))\n```\n\n### Option B: Manual Express\n\n```typescript\nimport express, { Response } from 'express'\nimport { Request, CloudAdapter, authorizeJWT, loadAuthConfigFromEnv } from '@microsoft\u002Fagents-hosting'\n\nconst authConfig = loadAuthConfigFromEnv()\nconst adapter = new CloudAdapter(authConfig)\nconst app = express()\n\napp.use(express.json())\napp.use(authorizeJWT(authConfig))\n\napp.post('\u002Fapi\u002Fmessages', async (req: Request, res: Response) => {\n  await adapter.process(req, res, async (context) => await agent.run(context))\n})\n\napp.listen(process.env.PORT || 3978)\n```\n\n### Proactive Messaging\n\nSave a reference during a turn, then use `adapter.continueConversation` from any route. `req.user` comes from `authorizeJWT` middleware.\n\n```typescript\nimport { ConversationReference } from '@microsoft\u002Fagents-activity'\n\n\u002F\u002F During a turn — save the reference\nconst ref = ctx.activity.getConversationReference()\nconversationReferences[ref.conversation.id] = ref\n\n\u002F\u002F In a proactive route\napp.get('\u002Fapi\u002Fnotify', async (req, res) => {\n  for (const ref of Object.values(conversationReferences)) {\n    await adapter.continueConversation(req.user!, ref, async (ctx) => {\n      await ctx.sendActivity('Proactive message')\n    })\n  }\n  res.json({ ok: true })\n})\n```\n\n## Validating Your Configuration\n\n### 1. Validate bot credentials (clientId \u002F clientSecret \u002F tenantId)\n\nThis tests that your Entra app registration credentials are correct and can authenticate with the Bot Framework. A successful response includes `access_token`; an error response includes `error` and `error_description`.\n\n```bash\ncurl -s -X POST \\\n  \"https:\u002F\u002Flogin.microsoftonline.com\u002F$tenantId\u002Foauth2\u002Fv2.0\u002Ftoken\" \\\n  -d \"grant_type=client_credentials\\\n&client_id=$clientId\\\n&client_secret=$clientSecret\\\n&scope=https:\u002F\u002Fapi.botframework.com\u002F.default\" \\\n  | jq '{token_type, expires_in, error, error_description}'\n```\n\nCommon errors:\n- `AADSTS700016` — `clientId` not found in tenant (wrong ID or wrong tenant)\n- `AADSTS7000215` — invalid `clientSecret` (expired or incorrect)\n- `AADSTS90002` — `tenantId` not found\n\n### 2. Validate the agent is running and reachable\n\n```bash\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n  -X POST http:\u002F\u002Flocalhost:3978\u002Fapi\u002Fmessages \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{}'\n```\n\n- `401` — agent is running; JWT auth rejected the empty request (expected — means auth is working)\n- `000` or connection refused — agent is not running or wrong port\n- `200` — agent is running with auth disabled (local dev with blank `clientId`)\n\n### 3. Validate an OAuth connection name\n\nOAuth connection names (set via `AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName`) can only be tested end-to-end through a real sign-in flow. Use the Azure portal:\n\n**Azure Portal → Your Bot Resource → Settings → OAuth Connection Settings → [your connection] → Test Connection**\n\nThis confirms the connection name matches, the OAuth app has the right scopes, and the redirect URI is configured correctly.\n\n## Local Testing with Agents Playground\n\nThe Agents Playground lets you test your agent locally without deploying to Azure or configuring a Bot resource. It acts as a mock connector service and channel client.\n\n**Install:**\n```bash\nnpm install -g agentsplayground\n```\n\n### Recommended package.json scripts\n\nInclude these scripts when creating a new agent's `package.json`. The `test` script starts the agent and playground together in parallel — no separate terminals needed:\n\n```json\n\"scripts\": {\n  \"prebuild\": \"npm ci\",\n  \"build\": \"tsc --build\",\n  \"prestart\": \"npm run build\",\n  \"prestart:anon\": \"npm run build\",\n  \"start:anon\": \"node .\u002Fdist\u002Findex.js\",\n  \"start\": \"node --env-file .env .\u002Fdist\u002Findex.js\",\n  \"test-tool\": \"agentsplayground -c emulator\",\n  \"test\": \"npm-run-all -p -r start:anon test-tool\"\n}\n```\n\n- `npm start` — builds and runs with `.env` credentials\n- `npm test` — builds, starts the agent without auth (`start:anon`), and launches the playground in parallel. Use this for quick local dev without needing an `.env` file.\n- `-c emulator` — uses the emulator channel (no auth required). Change to `msteams`, `webchat`, etc. as needed.\n- Requires `npm-run-all` as a dev dependency: `npm install -D npm-run-all`\n\n**With authentication** (for testing OAuth\u002Fsign-in flows):\n```bash\nagentsplayground -c msteams \\\n  --client-id \u003Cyour-app-id> \\\n  --client-secret \u003Cyour-secret> \\\n  --tenant-id \u003Cyour-tenant-id>\n```\n\n**Channel options** (`-c`): `msteams`, `webchat`, `directline`, `emulator`, `agents`\n\n## AgentApplication Patterns\n\n**Routing**\n```typescript\nthis.onMessage('\u002Fcmd', handler)              \u002F\u002F exact command\nthis.onActivity('message', handler)          \u002F\u002F all messages\nthis.onConversationUpdate('membersAdded', handler)\nthis.onActivity('invoke', handler)\nthis.onActivity('message', fallback, [], RouteRank.Last) \u002F\u002F fallback\n```\n\n**TurnState** — dot-notation keys auto-scoped to conversation\u002Fuser\u002Ftemp:\n```typescript\nconst count = state.getValue('conversation.counter') || 0\nstate.setValue('conversation.counter', count + 1)\nstate.deleteValue('conversation.counter')\n```\n\n**Storage backends**\n\n| Backend | Use case |\n|---|---|\n| `MemoryStorage` | Local dev only — not persistent |\n| `BlobsStorage` | Azure Blob — production |\n| `CosmosDbPartitionedStorage` | CosmosDB — production |\n\n## Authorization (User Token Flow)\n\n```typescript\nclass MyAgent extends AgentApplication\u003CTurnState> {\n  constructor() {\n    super({\n      storage: new MemoryStorage(),\n      authorization: {\n        graph: {\n          name: 'GraphOAuthConnection', \u002F\u002F OAuth connection name in Azure Bot resource\n          title: 'Sign in with Microsoft',\n          text: 'Please sign in to continue',\n        }\n      }\n    })\n\n    this.onSignInSuccess(async (ctx, state) => {\n      const { token } = await this.authorization.getToken(ctx, 'graph')\n      \u002F\u002F use token to call external APIs\n      await ctx.sendActivity('Signed in!')\n    })\n\n    this.onSignInFailure(async (ctx, state, authId, err) => {\n      await ctx.sendActivity(`Sign-in failed: ${err}`)\n    })\n\n    \u002F\u002F Protect a route — SDK sends the OAuth card automatically if not signed in\n    this.onActivity('message', async (ctx, state) => {\n      const { token } = await this.authorization.getToken(ctx, 'graph')\n      \u002F\u002F token is guaranteed here — route won't run until user is signed in\n    }, ['graph'])\n\n    \u002F\u002F Sign out from all providers\n    this.onMessage('\u002Flogout', async (ctx, state) => {\n      await this.authorization.signOut(ctx, state)\n      await ctx.sendActivity('Signed out.')\n    })\n  }\n}\n```\n\n`name` can also be provided via environment variable `AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName` (where `graph` is the handler key) and omitted from code.\n\n**OBO (on-behalf-of) — exchange user token for a downstream service token:**\n```typescript\nconst { token } = await this.authorization.exchangeToken(ctx, 'graph', {\n  scopes: ['https:\u002F\u002Fgraph.microsoft.com\u002F.default']\n})\n\u002F\u002F use token to call Graph or other downstream APIs\n```\n\n**Agentic auth** (agent-to-agent, no user prompt):\n```typescript\nauthorization: { agentic: { type: 'AgenticUserAuthorization' } }\n\u002F\u002F env: AgentApplication__UserAuthorization__Handlers__agentic__Settings__type=AgenticUserAuthorization\n\u002F\u002F env: AgentApplication__UserAuthorization__Handlers__agentic__Settings__scopes=https:\u002F\u002Fgraph.microsoft.com\u002F.default\n```\n\n## Cards\n\nRead [references\u002Fcards.md](references\u002Fcards.md) when working with Adaptive Cards, Hero Cards, Thumbnail Cards, or other card types.\n\n## Streaming\n\nRead [references\u002Fstreaming.md](references\u002Fstreaming.md) when implementing streaming responses.\n\n## OpenTelemetry \u002F Observability\n\nUse the `agents-sdk-typescript-otel` skill for OpenTelemetry initialization, SDK\ntraces and metrics, OTLP exporters, structured logs, safe custom\ninstrumentation, span-category filtering, Azure Monitor, validation, and the\nlocal Aspire Dashboard.\n\n## Common Mistakes\n\n**1. Wrong field name on ConversationReference**\n\n```typescript\n\u002F\u002F WRONG\nconst ref: ConversationReference = { bot: { id: appId } }\n\n\u002F\u002F CORRECT\nconst ref: ConversationReference = { agent: { id: appId } }\n```\n\n**2. JwtPayload.aud is string | string[]**\n\n```typescript\n\u002F\u002F WRONG\nconst appId = payload.aud\n\n\u002F\u002F CORRECT\nconst appId = Array.isArray(payload.aud) ? payload.aud[0] : payload.aud\n```\n\n**3. Adapter callbacks swallow exceptions**\n\n```typescript\n\u002F\u002F WRONG — error is lost\nawait adapter.continueConversation(identity, ref, async (ctx) => {\n  throw new Error('something failed') \u002F\u002F swallowed\n})\n\n\u002F\u002F CORRECT — capture and rethrow\nlet capturedError: Error | undefined\nawait adapter.continueConversation(identity, ref, async (ctx) => {\n  try {\n    await doWork(ctx)\n  } catch (err) {\n    capturedError = err as Error\n  }\n})\nif (capturedError) throw capturedError\n```\n\n**4. startServer() returns Express — add routes to the return value**\n\n```typescript\n\u002F\u002F WRONG — routes never registered\nconst app = express()\nstartServer(agent)\napp.get('\u002Fhealth', handler)\n\n\u002F\u002F CORRECT\nconst server = startServer(agent)\nserver.get('\u002Fhealth', handler)\n```\n\n### Wrong method names — `activity()` and `message()` don't exist\n\n`AgentApplication` uses `on`-prefixed method names. Common wrong guesses:\n\n```typescript\n\u002F\u002F ❌ wrong — these methods don't exist\napp.activity('message', handler)\napp.message(handler)\n\n\u002F\u002F ✅ correct\napp.onActivity('message', handler)\napp.onMessage('\u002Fhelp', handler)\napp.onConversationUpdate('membersAdded', handler)\n```\n\n## Contributing\n\nIf you hit a problem this skill couldn't solve, found a workaround, or noticed something wrong or outdated, that's valuable — please help improve this skill for everyone.\n\nDraft a suggested issue title and body based on the conversation, then ask the user to open it at: https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fagents\u002Fissues\u002Fnew\n\nA good issue includes:\n- What the user was trying to do\n- What went wrong (errors, unexpected behavior)\n- What worked — including any workaround found during this conversation\n- Relevant code or config snippets\n",{"name":5,"description":7},"main","8171bc7e0ca3b8defd578a6bb317367c2901983f","agent-plugins\u002Fagents-for-js\u002Fskills\u002Fagents-sdk-typescript",347,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents","https:\u002F\u002Faka.ms\u002Fagentsdkdocs","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-11 23:01:25",{"source":8,"skillName":5,"commands":47,"prompt":57,"zipAvailable":58},[48,51,54],{"tool":49,"command":50},"npx","npx skills add microsoft\u002FAgents --skill agents-sdk-typescript",{"tool":52,"command":53},"bunx","bunx skills add microsoft\u002FAgents --skill agents-sdk-typescript",{"tool":55,"command":56},"pnpm","pnpm dlx skills add microsoft\u002FAgents --skill agents-sdk-typescript","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-js\u002Fskills\u002Fagents-sdk-typescript\u002FSKILL.md",true,[60,66,70],{"path":61,"resourceType":62,"resourceTypeDesc":63,"sizeBytes":64,"sourceHtmlUrl":65},"references\u002Fcards.md","REFERENCE","参考文档",1773,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-js\u002Fskills\u002Fagents-sdk-typescript\u002Freferences\u002Fcards.md",{"path":67,"resourceType":62,"resourceTypeDesc":63,"sizeBytes":68,"sourceHtmlUrl":69},"references\u002Fstreaming.md",409,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-js\u002Fskills\u002Fagents-sdk-typescript\u002Freferences\u002Fstreaming.md",{"path":71,"resourceType":62,"resourceTypeDesc":63,"sizeBytes":72,"sourceHtmlUrl":73},"TEMPLATE.md",6034,"https:\u002F\u002Fgithub.com\u002Fapache\u002Figgy\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fconnector-sink\u002FTEMPLATE.md",[75,93,111,126,139,148],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":31},"01M6PJCYCYJQDX318SQN3EBF0E","sync-teams-samples-to-agents-sdk","CI instructions for a bounded Teams SDK to Agents SDK sample synchronization using the selected language profile.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fautomation\u002Fteams-sample-sync\u002Fskills\u002Fsync-teams-samples-to-agents-sdk\u002FSKILL.md",[],[25,26,82,83,84,85,86,87,88,89,90,91,92],"sync","teams","sync teams samples to agents sdk","ci","synchronization","instructions","profile","language","sample","for","bounded",{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":99,"publishedAt":31},"01M6PJCFNGCX555YERYQ459JFE","teams-sdk-to-agents-sdk-typescript-migration","Migrate a JavaScript or TypeScript application using the Microsoft Teams SDK App runtime to Microsoft 365 Agents SDK while preserving its Teams behaviors. Use for Teams SDK migrations, including automated sample synchronization; use the separate Bot Framework migration skill for botbuilder applications.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-js\u002Fskills\u002Fteams-sdk-to-agents-sdk-typescript-migration\u002FSKILL.md",[],[83,24,25,26,27,100,101,102,103,104,105,90,106,107,86,108,91,109,110,9],"migration","teams sdk to agents sdk typescript migration","microsoft teams","applications","app","runtime","migrations","use","migrate","bot","javascript",{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":122,"publishedAt":31},"01M69B8QV24JVPXH25EH77X0SZ","teams-app-manifest","Create or audit a Microsoft Teams app manifest for an existing Microsoft 365 Agents SDK application by mapping declared intent and source-code evidence to released manifest capabilities. Use when manifest.json is missing, incomplete, or must be checked against implemented Teams features. Does not configure Microsoft Entra, Azure Bot, Developer Portal, or deployment unless separately requested.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-sdk-common\u002Fskills\u002Fteams-app-manifest\u002FSKILL.md",[117],{"categoryNo":118,"categoryName":119,"taxonomyType":120,"taxonomyTypeDesc":121},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[83,123,26,109,25,9,124,125],"teams app manifest","azure","deployment",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":31},"01M69B8MN62NBY93YTJAQG2Y81","agents-sdk-provision","Use when provisioning Azure resources for a Microsoft Agents SDK application — including creating an Azure Bot Service resource, setting up Entra app registrations, configuring identity credentials (UserManagedIdentity, FederatedCredentials, or ClientSecret), adding a Teams channel, running Bicep deployments for SSO, or setting up OAuth user sign-in connections via az CLI. Trigger even if the user doesn't say \"provision\" — use on requests like \"set up my bot on Azure\", \"deploy my bot\", \"configure Azure for my bot\", or \"get Teams SSO working.\" Applies to all languages (dotnet, Node.js, Python).","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-sdk-common\u002Fskills\u002Fagents-sdk-provision\u002FSKILL.md",[],[25,26,133,109,134,135,9,136,137,138,124,83],"agents sdk provision","cli","python","dotnet","identity","deploy",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":31},"01M69B8HFZ45NQGWQQD483TWPB","agents-sdk-to-prod","Assess, create, harden, deploy, or review production readiness of Python Microsoft 365 Agents SDK agents and their direct hosting\u002Foperations files. Use only for Agents SDK scenarios, not unrelated application hardening.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-to-prod\u002FSKILL.md",[],[146,26,25,9,135,147,138],"agents sdk to prod","review",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":160,"publishedAt":31},"01M69B8ENJGC9NPQBZAYAN4706","agents-sdk-python-otel","Use when adding, configuring, validating, or troubleshooting OpenTelemetry observability for a Microsoft 365 Agents SDK application in Python. Trigger when the user mentions OpenTelemetry, OTel, telemetry, traces, metrics, logs, OTLP, Aspire Dashboard, Application Insights, Azure Monitor, distributed tracing, custom tracers or meters, span sampling, or observing microsoft_agents SDK signals.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-python-otel\u002FSKILL.md",[154,157],{"categoryNo":155,"categoryName":156,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":158,"categoryName":159,"taxonomyType":120,"taxonomyTypeDesc":121},"01JBSEEDCAT000000000000033","数据分析师",[25,135,161,26,162,163,124,164,9,165,166,167,168],"otel","agents sdk python otel","aspire","telemetry","dashboard","distributed","aspire dashboard","monitor"]