CopilotKit / CopilotKit/outpost
Keep the Teams ack card out of shadow-mode runs
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7
- Forks
- 3
- Avg merge
- 7d 16h
- Merged PRs (30d)
- 15
Description
Shadow mode is the switch that lets Outpost run alongside an incumbent without machine-generated text reaching real reporters. The worker's gate covers the AI answer on every platform, and #233 is currently making the predicate itself fail closed rather than fail open on SHADOW_MODE=TRUE.
The Teams bot sits outside that gate. apps/teams-bot/src contains no reference to SHADOW_MODE or isShadowMode at all, and apps/teams-bot/src/handlers/message.ts:120 posts the acknowledgment card at ingest:
if (result.isNewTicket && !result.isOrphanedReply) {
const card = buildTicketCreatedCard({ ... });
const reply = MessageFactory.attachment(CardFactory.adaptiveCard(card));
await context.sendActivity(reply);
Teams is deliberately the only platform that still acknowledges — the comment above that block explains why, and the reasoning holds. But it means Teams is also the only platform whose ingest post the worker's gate structurally cannot cover, because it never goes through the worker.
So on a staging run with shadow mode on: the worker correctly withholds the AI answer, and the reporter has already been told in a real Teams channel that an AI answer is coming. A promise from staging, an answer from production, or a promise and nothing.
Two supporting bits worth fixing at the same time:
.env.example:41-42says the flag "covers EVERY platform (GitHub, Slack, Teams)". Not true today.docs/deployment.md:212says "When adding any new outbound post path, checkSHADOW_MODEbefore posting" — that's the instruction that produced the three duplicated comparisons #233 is consolidating. OnceisShadowMode()lands inshared, that line should name the helper.
Shape of the fix, once #233 merges:
import { isShadowMode } from '@copilotkit/outpost/shared';
if (result.isNewTicket && !result.isOrphanedReply) {
if (isShadowMode()) {
console.log(
`[Teams Bot] Shadow mode — ticket ${result.displayId} created, ack card withheld`,
);
} else {
await context.sendActivity(reply);
}
}
apps/teams-bot has no shadow-mode test today, so this wants one alongside — ideally using the importOriginal + spread mock so it exercises the real predicate rather than a copy of it.
Depends on #233 for the shared helper. Kept separate so that diff stays about the predicate.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/teams-bot/src/handlers/message.ts:120 and the shared helper from #233, then inspect the existing Teams bot test setup. Add coverage for withholding the acknowledgment card in shadow mode while preserving the normal path, and update .env.example:41-42 and docs/deployment.md:212 to describe the helper. Done means the real predicate is exercised and the Teams ack is absent only when shadow mode is enabled.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, documentation, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 70/100