All checks were successful
Build and Deploy Teams Planner Bot / build-and-run (push) Successful in 14s
4.7 KiB
4.7 KiB
Teams Planner Bot
MS Teams 봇. 사용자의 자연어 작업 보고를 LLM으로 분류해서 Microsoft Planner에 자동으로 task를 생성하거나 업데이트한다.
동작 개요
사용자 (Teams) → 봇 → OAuthPrompt 로그인 (최초 1회)
→ Graph로 본인 Plans/Buckets/최근 Tasks 조회
→ LLM(Claude 또는 Azure OpenAI)에게 발화 + 컨텍스트 전달
→ tool/function call로 {action, planId, ...} JSON 강제 추출
→ Planner Graph API로 create / patch
→ Adaptive Card로 결과 응답
구성
src/
index.ts # restify 서버, CloudAdapter
config/index.ts # 환경변수 로딩/검증
bot/PlannerBot.ts # 메시지 핸들러 + OAuth 다이얼로그 + 오케스트레이션
graph/
graphClientFactory.ts # 사용자 토큰을 받아 Graph Client 생성
plannerClient.ts # Plans/Buckets/Tasks 조회·생성·업데이트 (ETag 처리 포함)
llm/
types.ts # ClassifiedAction 등 공용 타입
prompt.ts # 시스템 프롬프트 + tool/function 스키마
coerce.ts # LLM JSON → ClassifiedAction 검증
claudeClassifier.ts # Anthropic Claude 구현 (tool_use 강제)
azureOpenAiClassifier.ts # Azure OpenAI 구현 (function calling 강제)
factory.ts # LLM_PROVIDER 기반 분기
cards/confirmationCard.ts # 결과 Adaptive Card
appPackage/manifest.json # Teams 앱 매니페스트 (개발자 포털에 업로드)
사전 준비 (Azure / Microsoft 365)
-
Azure AD 앱 등록 (Graph 위임 권한)
- Azure Portal → App registrations → New
- API permissions → Microsoft Graph → Delegated:
Tasks.ReadWriteGroup.Read.AllUser.Readoffline_access
- Grant admin consent
- Certificates & secrets → Client secret 발급
- 노트:
tenantId,clientId,clientSecret
-
Azure Bot 리소스
- Azure Portal → Create resource → Azure Bot (Multi Tenant)
- Microsoft App ID/Password 발급 → 노트
- Configuration → OAuth Connection Settings → Add
- Name:
GraphConnection(이 이름이.env의OAUTH_CONNECTION_NAME) - Service Provider:
Azure Active Directory v2 - Client id / secret: 1번에서 만든 값
- Tenant ID: 1번의 tenantId
- Token Exchange URL: 비워두기 (SSO 안 쓸 경우)
- Scopes:
Tasks.ReadWrite Group.Read.All User.Read offline_access
- Name:
- "Test Connection" 으로 토큰이 떨어지는지 확인
-
Teams 앱 매니페스트
appPackage/manifest.json의REPLACE_WITH_YOUR_BOT_APP_ID를 Azure Bot의 App ID로 치환color.png(192×192),outline.png(32×32) 아이콘을appPackage/에 추가- 폴더를 zip 으로 압축 → Teams 관리자 센터(또는 개발자 포털)에서 사이드로딩
로컬 실행
npm install
cp .env.example .env
# .env 채우기
npm run dev
다른 터미널에서 ngrok 등으로 외부 노출:
ngrok http 3978
ngrok URL을 Azure Bot의 Messaging endpoint 에 https://<ngrok>/api/messages 형태로 설정.
LLM 교체
.env 의 LLM_PROVIDER 만 바꾸면 됨:
claude→ANTHROPIC_API_KEY,CLAUDE_MODEL사용azure-openai→AZURE_OPENAI_*사용
두 구현 모두 동일한 LlmClassifier 인터페이스를 구현하므로 호출부 변경 없음.
알아두면 좋을 점 / 함정
- Planner write는 ETag 필수.
plannerClient.ts가 PATCH 직전 항상 GET으로 ETag를 받아If-Match에 넣는다. 만약 동시 편집이 잦은 환경이면 412 에러를 retry 로 감싸야 한다. /me/planner/plans는 사용자가 속한 그룹의 Plan 만 반환한다. 봇이 "보이지 않는다" 면 Teams 채널에 그 사용자가 멤버인지부터 확인.- OAuthPrompt 의 토큰은 Bot Framework 의 토큰 서비스(token.botframework.com)에 캐시된다.
logout명령으로 강제 갱신 가능. - MemoryStorage 는 개발용. 프로덕션은 CosmosDB/Blob 백엔드로 교체.
- 확장 아이디어:
- 다중 후보일 때 카드의
Action.Submit으로 사용자가 직접 plan 선택 - Plans/Buckets 캐시 (현재는 매 발화마다 다시 조회)
- 일/주간 요약 발송 (proactive messaging)
- 다중 후보일 때 카드의
다음 단계
npm install→ 의존성 받기- Azure AD 앱 등록 + Azure Bot 리소스 + OAuth Connection 설정
.env채우기npm run dev로 띄우고 ngrok 으로 노출- Teams 매니페스트 사이드로딩 → 개인 채팅으로 봇과 대화
"오늘 견적서 초안 작성 시작했어"같은 첫 발화로 테스트