mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-09 03:11:58 +00:00
fix(teams-pipeline): add skill asset and fix async test env
This commit is contained in:
parent
b79ef8827f
commit
729a659a3c
2 changed files with 64 additions and 14 deletions
50
skills/productivity/teams-meeting-pipeline/SKILL.md
Normal file
50
skills/productivity/teams-meeting-pipeline/SKILL.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
name: teams-meeting-pipeline
|
||||
description: "Operate the Teams meeting summary pipeline via Hermes CLI."
|
||||
version: 1.0.0
|
||||
author: Hermes Agent
|
||||
license: MIT
|
||||
prerequisites:
|
||||
env_vars: [MSGRAPH_TENANT_ID, MSGRAPH_CLIENT_ID, MSGRAPH_CLIENT_SECRET]
|
||||
commands: [hermes]
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [Teams, Microsoft Graph, Meetings, Productivity, Operations]
|
||||
---
|
||||
|
||||
# Teams Meeting Pipeline
|
||||
|
||||
Use this skill when the user asks to summarize a Teams meeting, extract action items, inspect pipeline status, replay a stored job, or validate Microsoft Graph meeting-ingest setup.
|
||||
|
||||
Prefer the Hermes CLI over ad hoc scripts. Route operator actions through the terminal tool with `hermes teams-pipeline ...`.
|
||||
|
||||
## When to use
|
||||
|
||||
- "Teams meeting ozetle"
|
||||
- "action item cikar"
|
||||
- "toplanti notu"
|
||||
- "pipeline durumu"
|
||||
- "replay job"
|
||||
|
||||
## Required environment
|
||||
|
||||
Set these in `~/.hermes/.env` before using the pipeline:
|
||||
|
||||
```bash
|
||||
MSGRAPH_TENANT_ID=...
|
||||
MSGRAPH_CLIENT_ID=...
|
||||
MSGRAPH_CLIENT_SECRET=...
|
||||
```
|
||||
|
||||
## Common commands
|
||||
|
||||
```bash
|
||||
hermes teams-pipeline list
|
||||
hermes teams-pipeline show <job-id>
|
||||
hermes teams-pipeline replay <job-id>
|
||||
hermes teams-pipeline fetch --meeting-id <meeting-id>
|
||||
hermes teams-pipeline token-health
|
||||
hermes teams-pipeline maintain-subscriptions
|
||||
```
|
||||
|
||||
Start with `validate`, `list`, or `show` when the user asks for status. Use `replay` only when they explicitly want to rerun a stored job. Use `fetch` for dry-run artifact checks before changing pipeline config.
|
||||
|
|
@ -360,7 +360,7 @@ class TestTeamsInteractiveSetup:
|
|||
assert "TEAMS_TENANT_ID=tenant-id" in env_text
|
||||
|
||||
class TestTeamsConnect:
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_connect_fails_without_sdk(self, monkeypatch):
|
||||
monkeypatch.setattr(_teams_mod, "TEAMS_SDK_AVAILABLE", False)
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
|
|
@ -369,7 +369,7 @@ class TestTeamsConnect:
|
|||
result = await adapter.connect()
|
||||
assert result is False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_connect_fails_without_credentials(self):
|
||||
adapter = TeamsAdapter(_make_config())
|
||||
adapter._client_id = ""
|
||||
|
|
@ -378,7 +378,7 @@ class TestTeamsConnect:
|
|||
result = await adapter.connect()
|
||||
assert result is False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_disconnect_cleans_up(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -400,7 +400,7 @@ class TestTeamsConnect:
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestTeamsSend:
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_send_returns_error_without_app(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -410,7 +410,7 @@ class TestTeamsSend:
|
|||
assert result.success is False
|
||||
assert "not initialized" in result.error
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_send_calls_app_send(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -426,7 +426,7 @@ class TestTeamsSend:
|
|||
assert result.message_id == "msg-123"
|
||||
mock_app.send.assert_awaited_once_with("conv-id", "Hello")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_send_handles_error(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -439,7 +439,7 @@ class TestTeamsSend:
|
|||
assert result.success is False
|
||||
assert "Network error" in result.error
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_send_typing(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -594,7 +594,7 @@ class TestTeamsMessageHandling:
|
|||
ctx.activity = activity
|
||||
return ctx
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_personal_message_creates_dm_event(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -610,7 +610,7 @@ class TestTeamsMessageHandling:
|
|||
event = adapter.handle_message.call_args[0][0]
|
||||
assert event.source.chat_type == "dm"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_group_message_creates_group_event(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -625,7 +625,7 @@ class TestTeamsMessageHandling:
|
|||
event = adapter.handle_message.call_args[0][0]
|
||||
assert event.source.chat_type == "group"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_channel_message_creates_channel_event(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -640,7 +640,7 @@ class TestTeamsMessageHandling:
|
|||
event = adapter.handle_message.call_args[0][0]
|
||||
assert event.source.chat_type == "channel"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_user_id_uses_aad_object_id(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -655,7 +655,7 @@ class TestTeamsMessageHandling:
|
|||
event = adapter.handle_message.call_args[0][0]
|
||||
assert event.source.user_id == "aad-stable-id"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_self_message_filtered(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -669,7 +669,7 @@ class TestTeamsMessageHandling:
|
|||
|
||||
adapter.handle_message.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_bot_mention_stripped_from_text(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
@ -687,7 +687,7 @@ class TestTeamsMessageHandling:
|
|||
event = adapter.handle_message.call_args[0][0]
|
||||
assert event.text == "what is the weather?"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.anyio
|
||||
async def test_deduplication(self):
|
||||
adapter = TeamsAdapter(_make_config(
|
||||
client_id="bot-id", client_secret="secret", tenant_id="tenant",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue