关于 agent-teams
agent-teams 是供 AI Agent 和用户通过命令行操作 Microsoft Teams 的 TypeScript 工具,支持团队与账户切换,以及消息、聊天、频道和文件操作。它提供设备代码登录和本地令牌提取两种认证方式。
主要功能
- 01发送和搜索消息
- 02管理聊天与频道
- 03切换团队和账户
- 04上传和下载文件
- 05登录或提取令牌
适用场景
- 01由 AI Agent 发送消息
- 02查看频道或聊天记录
- 03在多个 Teams 团队间操作
- 04共享或获取 Teams 文件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agent-messenger/ agent-messenger --skill agent-teams安装后在 Claude Code 中输入/agent-teams确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/authentication.mdcommon-patterns.mdtemplates/monitor-channel.shpost-message.shteam-summary.sh详细介绍
Agent Teams
一个 TypeScript 命令行工具,可让 AI Agent 和人类通过简单的命令界面与 Microsoft Teams 交互。支持从 Teams 桌面应用无缝提取令牌(也可回退到浏览器提取),并支持多个团队。
Quick Start
# Get team snapshot (credentials are extracted automatically)
agent-teams snapshot
# Send a message
agent-teams message send <team-id> <channel-id> "Hello from AI agent!"
# List channels
agent-teams channel list <team-id>
Authentication
有两种同等地位的登录方式,可按需选择:
agent-teams auth login(工作/学校或个人 Microsoft 账户)——使用设备代码登录。打开显示的网址,输入代码,然后在浏览器中批准。无需桌面应用或浏览器提取。系统会提示输入 Microsoft 邮箱(也可传入--email <email>),并自动检测工作账户或个人账户,然后启动对应流程;传入--account-type work|personal可强制指定账户类型并跳过检测。只有auth login会存储message search所需的 AAD 刷新令牌。agent-teams auth extract——从 Teams 桌面应用中零配置提取,若失败则回退到 Chromium 浏览器。适合已在本地登录 Teams 的情况。此方式只会获取 Skype 令牌,足以发送消息,但不能用于message search(见下文)。
如果尚未存储凭据,首次使用任何命令时也会自动提取凭据,因此 auth extract 可能会在后台静默执行。
Teams 令牌的有效期较短(提取的令牌为 60-90 分钟,设备代码令牌为几小时)。设备代码账户(auth login)会静默刷新——CLI 会使用已存储的刷新令牌重新生成过期令牌,无需重新登录。只要你仍登录着 Teams 桌面应用或受支持的浏览器,提取账户就会自动重新提取;如果失败,请重新运行 auth extract(或切换到 auth login)。
非交互式 auth login(Agent / CI)
没有 TTY 时,auth login 分为两次调用:
# 1. Start — returns verification_uri, user_code, and device_code as JSON.
# Pass --email to auto-detect the account type (no prompt without a TTY),
# or --account-type work|personal to force it.
agent-teams auth login --email <email>
# 2. After the user approves in a browser, finish with the device_code
agent-teams auth login --device-code <device_code>
--client-id <id> 可在任一调用中覆盖 AAD 客户端 ID(或设置 AGENT_TEAMS_CLIENT_ID)。--account-type <work|personal> 用于选择账户(默认值为 work);该设置会在两次调用的流程中保留,因此以非交互方式登录个人账户时,需在两次调用中都传入此参数。
多团队支持
# List all available teams
agent-teams team list
# Switch to a different team
agent-teams team switch <team-id>
# Show current team
agent-teams team current
# Check auth status (includes token expiry info)
agent-teams auth status
多账户支持(工作 / 个人)
# Switch between work and personal accounts
agent-teams auth switch-account work
agent-teams auth switch-account personal
# Use a specific account for one command (without switching)
agent-teams snapshot --account work
Memory
Agent 会维护 ~/.config/agent-messenger/MEMORY.md 文件,作为跨会话的持久记忆。该文件由 Agent 管理——CLI 不会读取或写入此文件。请使用 Read 和 Write 工具管理记忆文件。
读取记忆
在每项任务开始时,使用 Read 工具读取 ~/.config/agent-messenger/MEMORY.md,加载之前发现的团队 ID、频道 ID、用户 ID 和偏好设置。
- 如果文件尚不存在,也没关系——无需读取即可继续,并在首次获得有用信息时创建该文件。
- 如果无法读取文件(权限问题、目录不存在),则不使用记忆继续操作——不要报错。
写入记忆
发现有用信息后,使用 Write 工具更新 ~/.config/agent-messenger/MEMORY.md。以下情况应触发写入:
- 发现团队 ID 和名称后(通过
team list、snapshot等) - 发现有用的频道 ID 和名称后(通过
channel list、snapshot等) - 发现用户 ID 和名称后(通过
user list、user me等) - 用户提供别名或偏好后(“把这个称作站会频道”“我的主要团队是 X”)
- 发现频道结构后(标准频道或专用频道)
写入时,请包含完整文件内容——Write 工具会覆盖整个文件。
要存储的内容
- 团队 ID 及其名称
- 频道 ID、名称及所属团队
- 用户 ID 及显示名称
- 用户提供的别名(“站会频道”“主要团队”)
- 账户偏好(工作或个人)
- 交互过程中表达的任何用户偏好
不要存储的内容
绝不存储令牌、凭据或任何敏感数据。绝不存储完整消息内容(仅存储 ID 和频道上下文)。绝不存储文件上传内容。
处理过期数据
如果记忆中的 ID 返回错误(找不到频道、找不到团队),请从 MEMORY.md 中删除。不要盲目信任记忆中的数据——发现异常时应进行验证。与其使用可能已过期的记忆 ID,不如重新列出。
格式 / 示例
# Agent Messenger Memory
## Teams
- `team-id-1` — Acme Corp (default, work account)
- `team-id-2` — Side Project (personal account)
## Channels (Acme Corp)
- `channel-id-1` — General
- `channel-id-2` — Engineering
- `channel-id-3` — Standups
## Users (Acme Corp)
- `user-id-1` — Alice (engineering lead)
- `user-id-2` — Bob (backend)
## Aliases
- "standup" → `channel-id-3` (Standups in Acme Corp)
- "main team" → `team-id-1` (Acme Corp)
## Notes
- User prefers work account by default
- Main team is "Acme Corp"
记忆功能可让你跳过重复的
channel list和team list调用。如果你已在之前的会话中知道某个 ID,请直接使用。
命令
身份验证命令
# Sign in via device code (personal Microsoft accounts).
agent-teams auth login
agent-teams auth login --device-code <code> # finish a non-interactive login
# Extract token from Teams desktop app or browser (usually automatic)
agent-teams auth extract
agent-teams auth extract --debug
agent-teams auth extract --browser-profile ~/browser-data
agent-teams auth extract --browser-profile ~/work-profile --browser-profile ~/personal-profile
# --browser-profile accepts repeatable or comma-separated Chromium profile/user-data dirs
# Check auth status (includes token expiry info)
agent-teams auth status
# Logout from Microsoft Teams
agent-teams auth logout
# Switch between work and personal accounts
agent-teams auth switch-account <account-type>
agent-teams auth switch-account work
agent-teams auth switch-account personal
Whoami 命令
# Show current authenticated user
agent-teams whoami
agent-teams whoami --pretty
输出包含已通过身份验证的用户身份信息。
消息命令
# Send a message
agent-teams message send <team-id> <channel-id> <content>
agent-teams message send <team-id> 19:[email protected] "Hello world"
# Send a rich-text message written in markdown
agent-teams message send <team-id> <channel-id> "## Deploy done
- service A
- service B" --format markdown
# List messages
agent-teams message list <team-id> <channel-id>
agent-teams message list <team-id> 19:[email protected] --limit 50
# Get a single message by ID
agent-teams message get <team-id> <channel-id> <message-id>
# Delete a message
agent-teams message delete <team-id> <channel-id> <message-id> --force
# Search messages across Teams (requires `auth login` — see Authentication)
agent-teams message search <query>
agent-teams message search "deploy" --limit 10 --from 0
message search 需要使用 auth login 登录的账户:它会使用 AAD 令牌查询 Microsoft 的 Substrate 搜索 API,而基于 Cookie 的 auth extract 无法提供该令牌。仅使用 Cookie 的账户会收到清晰的错误提示,告知你运行 auth login。--limit 必须为正整数(默认值为 20);--from 是用于分页的非负偏移量(默认值为 0)。
频道命令
# List channels in a team
agent-teams channel list <team-id>
# Get channel info
agent-teams channel info <team-id> <channel-id>
agent-teams channel info <team-id> 19:[email protected]
# Get channel history (alias for message list)
agent-teams channel history <team-id> <channel-id> --limit 100
聊天命令
适用于没有团队或频道的个人 Microsoft 账户(@outlook.com / @live.com)——这类账户只有 1:1 聊天、群聊和个人聊天线程。工作账户也可以使用这些功能进行 1:1 聊天和群聊。
# List 1:1, group, and self chats
agent-teams chat list
# Get chat message history
agent-teams chat history <chat-id> --limit 100
# Get a single chat message
agent-teams chat get <chat-id> <message-id>
# Send a message to a chat
agent-teams chat send <chat-id> "Hello"
agent-teams chat send <chat-id> "**Important**: see the [board](https://example.com)" --format markdown
# Edit one of your own chat messages
agent-teams chat edit <chat-id> <message-id> "Updated text"
agent-teams chat edit <chat-id> <message-id> "Fixed \`bug\`" --format markdown
聊天 ID 的格式为 19:[email protected](1:1)或 19:[email protected](群聊)。可通过 chat list 获取。48:notes 聊天(type: self)是你的个人“发给自己”的便笺线程。
chat edit 只能编辑你自己的消息,而且仅适用于聊天——无法通过此 API 编辑 Teams 频道消息。
消息内容(文本、HTML、文件)
来自 chat history、chat get、message list/get/replies 和 channel history 的消息包含:
content— 纯文本(段落以换行分隔,链接格式为text (url);数字实体和常见命名实体(例如&、 、—)会被解码,较少见的命名实体则保持原样)html— 仅适用于富文本消息的原始 HTML;可用于查看图片在文本中的位置files— 消息中所有可下载的 URL:先列出内嵌图片(按顺序),然后是附件
使用 agent-teams file download <url> [output-path] 下载 files 中的任意条目。
消息格式
message send、chat send 和 chat edit 接受 --format <text|markdown|html>(默认为 text)。
在 text 模式下,内容会进行 HTML 转义,因此 <、> 和 & 会按原样发送。
在 markdown 模式下,发送前会将内容转换为 HTML。支持的语法:
| 语法 | 渲染效果 |
|---|---|
# Heading 至 #### Heading | 标题 |
##### Heading、###### Heading | 不支持 — 与正文无法区分 |
**bold**、_italic_、***bold italic*** | 强调 |
`inline code` | 行内代码 |
| 三反引号围栏 | 围栏代码块,不带语法高亮 |
- item | 项目符号列表 |
1. item | 编号列表 |
> quote | 引用块 |
[label](https://example.com) | 链接 |
--- | 水平分隔线 |
标题级别 5 和 6 不可用:Teams 客户端会以正文大小渲染 <h5> 和 <h6>,因此它们与周围文本无法区分。标题最多使用到 ####。围栏代码块会渲染为等宽字体块,但不会进行语法高亮——语言标签(```ts)会被接受,但随后忽略。这两种行为均已通过实时账户验证。
链接仅允许使用 http:、https:、mailto:、相对于根路径的 URL(/)和锚点 URL(#);其他内容会渲染为纯文本。
在 html 模式下,内容会经过标签白名单过滤,而不是原样发送。需要使用 Markdown 无法表达的 Teams 专用标记(最常见的是 @提及)时,请使用此模式:
agent-teams message send <team-id> <channel-id> "Hey <at id=\"29:abc\">John</at>, build is ready" --format html
允许的标签:at、a、b、i、u、s、strong、em、code、pre、br、p、ul、ol、li、blockquote、h1–h6、hr。<at> 仅保留其 id 属性;<a> 仅保留 href,且仅当其符合与 Markdown 模式相同的 URL 白名单时才会保留;其他所有标签都不保留任何属性。不在列表中的内容——<script>、<img>、on* 事件属性,以及格式错误或无法识别的标签——会被转义或移除,而不会原样传递。
白名单限制了潜在影响范围,但这并不意味着该模式可以安全处理任意输入:只传入你自行构造的内容。不可信输入应使用 text 模式。
团队命令
# List all teams
agent-teams team list
# Get team info
agent-teams team info <team-id>
# Switch active team
agent-teams team switch <team-id>
# Show current team
agent-teams team current
# Remove a team from config
agent-teams team remove <team-id>
用户命令
# List team members
agent-teams user list <team-id>
# Get user info
agent-teams user info <user-id>
# Get current user
agent-teams user me
表情回应命令
# Add reaction (use emoji name)
agent-teams reaction add <team-id> <channel-id> <message-id> <emoji>
agent-teams reaction add <team-id> 19:[email protected] 1234567890 like
# Remove reaction
agent-teams reaction remove <team-id> <channel-id> <message-id> <emoji>
文件命令
# Upload file
agent-teams file upload <team-id> <channel-id> <path>
agent-teams file upload <team-id> 19:[email protected] ./report.pdf
# List files in channel
agent-teams file list <team-id> <channel-id>
# Get file info
agent-teams file info <team-id> <channel-id> <file-id>
# Download a file (to a path or directory; defaults to the current dir)
agent-teams file download <team-id> <channel-id> <file-id>
agent-teams file download <team-id> <channel-id> <file-id> ./report.pdf
agent-teams file download <team-id> <channel-id> <file-id> ./downloads/ --pretty
# Download a URL from a message's `files` (inline image or attachment)
agent-teams file download <url> ./downloads/
URL 下载输出:{ "name", "size", "content_type", "path" }。当响应中没有文件名时,内嵌图片会回退使用其 Teams 对象 ID(例如 0-skr-d1-....jpg)。
file download 输出:{ "id", "name", "size", "content_type", "path" },其中 path 是文件写入的位置。内嵌图片/附件会使用提取出的 Skype 令牌下载,且适用于任何已登录账户;SharePoint/OneDrive 文档则通过 Microsoft Graph 下载,并要求使用 auth login 账户(仅 Cookie 的 auth extract 账户会收到明确错误,提示你运行 auth login)。
快照命令
获取供 AI Agent 使用的团队概览(默认简要):
# Brief snapshot (default) — fast, minimal API calls
agent-teams snapshot
# Full snapshot — includes messages and members (slow, large output)
agent-teams snapshot --full
# Filtered full snapshots
agent-teams snapshot --full --channels-only
agent-teams snapshot --full --users-only
# Limit messages per channel (only with --full)
agent-teams snapshot --full --limit 10
默认返回简要 JSON,包含:
- 团队元数据(id、name)
- 频道(id、name)
- 后续命令提示
使用 --full 时,返回完整 JSON,包含:
- 团队元数据(id、name)
- 频道(id、name、type、description)
- 最近的消息(id、content、author、timestamp)
- 成员(id、displayName、email)
输出格式
JSON(默认)
所有命令默认输出 JSON,供 AI 使用:
{
"id": "19:[email protected]",
"content": "Hello world",
"author": "John Doe",
"timestamp": "2024-01-15T10:30:00.000Z"
}
Pretty(人类可读)
使用 --pretty 标志输出格式化内容:
agent-teams channel list --pretty
与 Discord/Slack 的主要区别
| 功能 | Teams | Discord | Slack |
|---|---|---|---|
| 服务术语 | 团队 | Guild | 工作区 |
| 频道标识符 | UUID 格式(19:[email protected]) | Snowflake ID | 频道名称或 ID |
| 令牌存储 | Cookies SQLite | LevelDB | LevelDB |
| 令牌过期 | 60-90 分钟 | 很少过期 | 很少过期 |
| 提及 | <at id="user-id">Name</at>(需要 --format html) | <@user_id> | <@USER_ID> |
重要:Teams 使用 UUID 风格的频道 ID(例如 19:[email protected])。不能直接使用频道名称——请先使用 channel list 查找 ID。
常见模式
典型的 AI Agent 工作流请参阅 references/common-patterns.md。
模板
可运行示例请参阅 templates/ 目录:
post-message.sh- 发送消息并处理错误monitor-channel.sh- 监控频道中的新消息(含令牌刷新)team-summary.sh- 生成团队摘要
错误处理
所有命令均返回一致的错误格式:
{
"error": "Not authenticated. Run \"auth extract\" first."
}
常见错误:
Not authenticated:没有有效令牌(自动提取失败——请参阅故障排除)Token expired:令牌已过期,且自动刷新失败——请参阅故障排除No current team set:请先运行team switch <id>。个人账户没有团队——请改用chat list/chat history/chat sendMessage not found:消息 ID 无效Channel not found:频道 ID 无效401 Unauthorized:令牌已过期,且自动刷新失败——请参阅故障排除
配置
凭据存储在 ~/.config/agent-messenger/teams-credentials.json 中(权限为 0600)。格式和安全详情请参阅 references/authentication.md。
SDK:编程式用法
TeamsClient 可作为 TypeScript SDK 使用,用于构建脚本和自动化流程。
设置
import { TeamsClient } from 'agent-messenger/teams'
const client = await new TeamsClient().login()
或手动管理凭据:
import { TeamsClient, TeamsCredentialManager } from 'agent-messenger/teams'
const manager = new TeamsCredentialManager()
const creds = await manager.getTokenWithExpiry()
if (!creds) {
throw new Error('Teams token not found. Run auth extract first.')
}
const client = await new TeamsClient().login({ token: creds.token, tokenExpiresAt: creds.tokenExpiresAt })
示例
// List teams
const teams = await client.listTeams()
// List channels in a team
const channels = await client.listChannels(teams[0].id)
// Send a message
const msg = await client.sendMessage(teams[0].id, channels[0].id, 'Hello from SDK!')
// React to it
await client.addReaction(teams[0].id, channels[0].id, msg.id, 'like')
// Upload a file
await client.uploadFile(teams[0].id, channels[0].id, './report.pdf')
实时事件
通过内部 trouter WebSocket 实时流式接收 Teams 聊天消息——以用户身份连接,无需机器人或公共端点。需要登录 Teams 桌面应用。
import { TeamsClient, TeamsListener } from 'agent-messenger/teams'
const client = await new TeamsClient().login()
const listener = new TeamsListener(client)
listener.on('message', async (message) => {
console.log(`New message in ${message.chatId}: ${message.content}`)
// Channel messages carry team/channel context and parsed @mentions.
if (message.conversationType === 'channel') {
for (const mention of message.mentions) {
console.log(`Mentioned: ${mention.displayName} (${mention.mri})`)
}
await client.sendMessage(message.teamId!, message.channelId!, 'On it 👍')
}
})
await listener.start()
每条 message 都是一个 TeamsRealtimeMessage:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 消息 ID |
chatId | string | 会话 ID(保持不变) |
conversationType | 'chat' | 'channel' | 团队频道消息时为 'channel' |
teamId | string? | 频道消息会设置此字段(与 sendMessage 搭配使用) |
channelId | string? | 频道消息会设置此字段(与 sendMessage 搭配使用) |
content | string | 纯文本(保留段落分隔,已解码实体) |
html | string? | 原始 HTML,仅限富文本消息 |
files | string[]? | 可下载的 URL:先列出内嵌图片,再列出附件 |
mentions | TeamsMention[] | 始终存在;没有 @mentions 时为空。每项格式为 { id, mri?, displayName } |
author | { id, displayName } | 发送者(保持不变) |
messageType | string | 例如 Text、RichText/Html |
timestamp | string | ISO 时间戳 |
完整 API 参考
完整的方法签名、类型、架构和示例请参阅 Teams SDK 文档。
限制
- 实时事件仅限 SDK(
TeamsListener);CLI 没有watch命令 - 不支持语音/视频频道
- 不支持团队管理(创建/删除频道、角色)
- 个人账户:仅支持聊天(不支持团队/频道);请使用
chat命令 - 不支持会议
- 不支持 webhook
- 仅支持纯文本消息(v1 不支持自适应卡片)
- 仅支持用户令牌(不支持应用令牌)
- 令牌有效期较短——设备代码(
auth login)账户会使用存储的刷新令牌在后台自动刷新;提取登录信息的账户也会自动刷新,但需要 Teams 桌面应用或浏览器仍处于登录状态
故障排除
agent-teams: command not found
agent-teams 不是 npm 包名称。 npm 包名为 agent-messenger。
如果已全局安装该包,请直接使用 agent-teams:
agent-teams team list
如果未安装该包,默认使用 npx -y。不要询问用户要使用哪种包运行器——直接运行:
npx -y agent-messenger teams team list
bunx agent-messenger teams team list
pnpm dlx agent-messenger teams team list
如果你已知用户偏好的包运行器(例如
bunx、pnpm dlx),则使用该运行器。
切勿运行 npx agent-teams、bunx agent-teams 或 pnpm dlx agent-teams——由于 agent-teams 不是 npm 包名称,这些命令会失败或安装错误的包。
有关其他故障排除信息(身份验证信息提取、令牌过期、权限),请参阅 references/authentication.md。