- **무료 답변은 숨겨집니다** — 캐시된 답변이나 자유 모델 답변에는 바닥글이 표시되지 않습니다.
- **Emoji 토글** — 데이터를 유지하면서 사용자 구성을 통해 `💰` 접두사를 비활성화합니다.
- **Feishu 카드** — 비용은 타임스탬프와 함께 기본 `note` 요소로 표시됩니다.
- **정밀도** — 정확한 추적을 위해 비용은 항상 소수점 이하 4자리로 표시됩니다.
이는 추가 구성 없이 자동으로 작동합니다. 비용 데이터는 스트리밍 중에 하네스 `token_usage` 이벤트에서 추출됩니다.
### 스마트 메시지 분할
긴 메시지는 자연스러운 경계에서 자동으로 분할됩니다.
- 코드 펜스 상태 머신은 코드 블록이 청크 전체에서 적절하게 닫히고 다시 열리도록 보장합니다.
- 공백 및 구두점 경계에서 지능적인 줄 분할
- 의미 보존을 위해 구성 가능한 오버플로 허용 오차
- 채널당 길이 제한(예: Discord 2000자, Telegram 4096 HTML / 32000 Rich Message)
### 텔레그램 리치 메시지(봇 API 10.1)
텔레그램 채널은 3계층 대체를 통해 기본 리치 메시지 렌더링을 지원합니다.
1. **리치 메시지** — 테이블, LaTeX 수식 및 중첩 목록이 기본적으로 렌더링됩니다(32KB 제한).
2. **HTML** — ASCII 고정폭 테이블 저하로 자동 변환됨(4096 UTF-16 제한)
3. **일반 텍스트** — HTML 구문 분석이 실패할 경우 최후의 수단
스트리밍은 초기 토큰 깜박임을 억제하기 위해 최소 임계값이 20자인 **깜박임 없는 초안 미리 보기**(`sendRichMessageDraft` → `sendMessageDraft` → `editMessageText`)를 사용합니다. CJK 콘텐츠는 완전한 Rich 형식을 수신하며 성능 저하나 해결 방법이 없습니다.
## 그룹 채팅 기능
### 허용정책
에이전트가 그룹 채팅에서 응답하는 시기를 제어하는 세 가지 미리 설정된 정책은 다음과 같습니다.
| Policy | DM | Group |
|--------|-----|-------|
| OPEN | Allow all | Allow all (no mention needed) |
| SELECTIVE | Allow all | Mention required |
| STRICT | Mention required | Mention required |
### 그룹 트리거 모드
그룹 채팅에서 상담원이 활성화되는 시점을 세밀하게 제어할 수 있습니다.
| Mode | Behavior |
|------|----------|
| ALL | Every message in the group triggers the agent |
| MENTION_ONLY | Only responds when @mentioned |
| PREFIX | Responds when message starts with a configured prefix (prefix is auto-stripped) |
### 주제 바인딩
3계층 세분성은 다양한 에이전트를 다양한 대화 범위에 바인딩합니다.
- **스레드 수준**: 특정 주제/스레드에 바인딩됨
- **채팅 수준**: 특정 그룹/대화에 연결됨
- **채널 수준**: 전체 채널에 바인딩됨
조회 순서는 스레드→채팅→채널이며 기본 에이전트로 안전하게 대체됩니다.
### 주제 작업공간 바인딩(Vault/프로젝트)
원격 메시지가 빈 JIT 샌드박스에 들어가지 않도록 각 IM 주제를 실제 작업 공간에 바인딩합니다.
| Method | How |
|--------|-----|
| **GUI** | **Settings → Channel Routing** → per-topic **Project** dropdown |
| **IM** | `/bind workspace=project:<uuid>` or `/bind workspace=/path/to/vault` |
| **Combined** | `/bind agent=my-agent workspace=project:<uuid>` |
각 에이전트가 실행되기 전에 시스템은 WebUI 세션과 동일한 `resolve_effective_chat_workspace` 체인을 사용하여 주제 바인딩을 채팅 SSOT(`project_id` 또는 `workspace_dir`)에 동기화합니다. 바인딩을 해제하면 채팅의 두 필드가 모두 지워집니다. 프로젝트 또는 경로를 사용할 수 없는 경우 빈 샌드박스를 자동으로 사용하는 대신 큰 소리로 실행이 실패합니다.
**정직한 한계:** IM `/status`에는 여전히 `project:uuid`(친숙한 이름이 아님)가 표시됩니다. GUI 경로 선택기가 없습니다. — GUI 사용자가 프로젝트를 바인딩합니다. 경로 바인딩은 IM 우선입니다.
**테스트 범위:** 9개 서버 pytest 사례(동기화, topic_config 유효성 검사, 바인딩 해제 지우기, Effective_workspace 체인). 프런트엔드 라벨 도우미: 3 vitest 사례.
**대 OpenClaw:** OpenClaw은 에이전트 구성 수준에서 `workspaceDir`을 바인딩합니다(에이전트당 하나의 작업 영역). Myrm은 주제 세분화로 바인딩되므로 동일한 에이전트가 서로 다른 저장소를 가리키는 서로 다른 전보 스레드를 제공할 수 있습니다.
### 흑요석 금고 쓰기 충실도
주제가 Obsidian 볼트에 바인딩되면 에이전트 편집 내용이 **실제 볼트 파일**(사본 아님)로 이동됩니다. Myrm은 두 가지 코드 수준 보호 장치를 추가합니다.
1. **머리말 보존** — 본문을 편집하는 동안 LLM이 `---` YAML 블록을 삭제하는 경우 쓰기 가드는 저장하기 전에 사전 편집된 머리말을 다시 삽입합니다(`date:`, `tags:`, Dataview 필드는 그대로 유지됩니다).
2. **볼트 노트가 더 예뻐지지 않습니다** — FormatObserver는 `.obsidian/` 볼트 루트 아래의 `.md` 파일을 건너뛰므로 자동 서식 지정이 메타데이터를 제거할 수 없습니다.
**정직한 제한:** 블록 수준 재주입만 가능합니다(필드별 병합 아님). Wikilink 무결성은 `obsidian-notes` 기술에 의존합니다. 아직 볼트 전체 백링크 검사는 없습니다.
**테스트:** 44 pytest 사례(2026년 7월): 하네스 가드 + 서버 파서 + 서비스 통합 + 형식 관찰자.
### 스레드 후속 조치
상담원이 스레드에서 응답한 후 해당 스레드에 대해 **GroupFollowUpTracker**가 활성화됩니다(TTL: 10분). 이 기간 동안 동일한 스레드의 후속 메시지에는 @멘션이 필요하지 않습니다. 즉, 사람이 하는 것처럼 에이전트가 자동으로 대화를 계속합니다.
후속 작업을 중지하려면 스레드에서 `/mute`, `/shutup`, `闭嘴` 또는 `别吵`를 보내세요. 에이전트가 즉시 응답을 중지합니다. 재활성화하려면 상담원을 다시 @mention하면 됩니다.
### 게스트 멘션
에이전트에 대해 명시적으로 활성화되지 않은 그룹에서도 사용자는 일회성 응답을 위해 에이전트를 @멘션할 수 있습니다(게스트 모드가 활성화된 경우). 이를 통해 화이트리스트에 그룹을 추가하지 않고도 임시 AI 지원이 가능합니다.
### 정확한 봇 ID 매칭
모든 채널 공급자는 정확한 봇 신원 일치를 수행합니다. Telegram은 `bot_username`을 확인하고, Feishu는 `bot_open_id`을 확인하고, Teams는 `app_id`을 확인하고, WhatsApp은 `mentionedJids`을 확인합니다. 즉, @멘션은 35개 이상의 모든 채널에서 잘못된 트리거 없이 항상 올바른 봇으로 정확하게 라우팅됩니다.
### GroupContextBuffer
그룹 채팅의 트리거되지 않은 메시지는 그룹별 링 버퍼에 누적됩니다. 트리거 메시지(예: @agent)가 도착하면 버퍼가 비워지고 컨텍스트로 주입되어 에이전트가 그룹 토론에 대한 대화 인식을 제공합니다.
### 세션게이트
동일한 대화의 신속한 메시지는 반송 처리되고(기본 300ms 기간) 단일 요청으로 병합되어 중복 처리가 방지됩니다.
## 결정적 사전 LLM 처리
모든 인바운드 메시지는 모델에 도달하기 전에 LLM 비용이 전혀 들지 않는 5개 계층 처리를 거칩니다. 이는 일반적인 작업이 토큰을 소비하지 않고 밀리초 내에 응답함을 의미합니다.
| Layer | What it does | Latency |
|-------|-------------|---------|
| **Message Dedup** | TTL-based deduplication (`channel:message_id`) prevents Webhook retries from triggering duplicate processing | <0.1ms |
| **Slash Commands** | 21 system commands + dynamic Skill bindings + Agent routing — O(1) registry lookup | <0.1ms |
| **Risk Detection** | Compiled regex engine blocks or warns on sensitive content; ReDoS-safe with audit trail | <1ms |
| **FAQ Semantic Cache** | Embedding similarity + score/gap dual verification — cache hits return template answers instantly (40–100× faster than LLM) | 5–20ms |
| **Policy + Session Gate** | DM/Group policy enforcement, message debouncing (300ms), merge, and concurrency control | <1ms |
### 이것이 사용자에게 의미하는 것
- **일반적인 질문에 즉시 답변** — FAQ 조회는 LLM을 완전히 건너뛰어 시간과 비용을 모두 절약합니다.
- **민감한 콘텐츠는 자동으로 차단됨** — 수동 조정 없이 규정 준수 가능
- **대기 시간이 없는 빠른 명령** — `/stop`, `/new`, `/status`은 즉시 실행됩니다.
- **신속한 메시지는 적절하게 처리됨** — 버스트 메시지는 중복 처리되지 않고 병합됩니다.
- **토큰 낭비 없음** — AI 추론이 정말로 필요한 메시지만 모델에 도달합니다.
## 에이전트가 시작한 알림
에이전트는 구성된 채널에 사전에 알림을 푸시할 수 있으므로 수동 폴링이 필요하지 않습니다.
### 작동 방식
1. **에이전트 설정 → 알림 채널**에서 **현재 실행 중인** 통합(사람이 읽을 수 있는 이름이 포함된 동적 목록 - 새 채널은 프런트엔드 릴리스 없이 나타남)에서 채널을 선택한 다음, 페어링된 연락처에서 수신자를 선택합니다(또는 수동으로 ID를 입력합니다).
2. 에이전트는 경고가 필요할 때 `channel_notify_tool`을 호출합니다(작업 완료, 이상 탐지, 예약된 보고서 준비).
3. 선택적으로 파일 또는 이미지 첨부 - 올바른 미디어 유형 감지를 통해 로컬 경로 및 URL이 자동으로 확인됩니다.
4. 전달은 동시 성공/실패 결과(중요 채널 메시지와 동일한 재시도 정책)를 위해 `send_tracked`를 사용하며, 실행 후 잊어버리는 대기열 삭제가 아닙니다.
> **알림 전달 대비**: **에이전트 설정 → 알림 채널**은 `channel_notify_tool`만 허용 목록에 추가합니다. **설정 → 알림 전달**은 **시스템 이벤트**(OAuth, 예산, 페어링, 채널 상태)를 라우팅합니다. 그것들은 서로 바꿔 사용할 수 없습니다.
### 보안
| Layer | Protection |
|-------|-----------|
| Whitelist | Only user-configured targets are reachable — no arbitrary recipients |
| Rate limit | Per-session cap prevents notification spam (default: 10 per session) |
| Content cap | Messages exceeding `max_body_length` (4000 chars) are automatically truncated |
| Attachments | Local paths must stay within the agent workspace (`declared_allowed_roots`); URL filenames parsed safely (handles query params) |
| Audit trail | Every notification target used is recorded in session state |
| Sub-agent isolation | Sub-agents cannot call `channel_notify_tool` by default (harness L1 blocklist) |
| Failure visibility | Sync delivery failures enter DLQ and trigger a WebUI toast (presync dedupe; not persisted across restarts) |
| Layer | Server `outbound_notify/` (business layer, not harness kernel), co-located with ChannelGateway |
> **테스트 적용 범위(2026-07-07)**: **127 pytest + 1 라이브 에이전트 스트림 E2E(MiniMax-M2.7, RUN_E2E_TESTS=1) + 7 vitest + Chrome 전체 사용자 흐름 round42(소스 채팅 도구 단계 + 수신자 받은 편지함 UI)** 통과 — ChatChannel 인앱 받은 편지함 전달, DLQ/토스트 체인, 하위 에이전트 격리, 첨부 경로 샌드박스, 동적 실행 채널 선택기가 확인되었습니다.
### 예시 시나리오
- 예정된 작업은 오전 3시에 완료됩니다. → 상담원이 요약 + 보고서 PDF를 텔레그램으로 보냅니다.
- 장기 실행 코드 분석 완료 → 결과 + 생성된 차트가 Slack 채널로 푸시됨
- 모니터링 데이터에서 이상 징후 감지 → 구성된 대상에 대시보드 스크린샷을 전송하여 알림
## 웹 푸시(오프라인 알림)
브라우저를 닫은 후에도 중요한 알림을 받습니다. 기본 앱이 필요하지 않습니다.
PWA가 닫히거나 백그라운드 상태가 되면 서버는 W3C 웹 푸시 표준(VAPID)을 통해 푸시 알림을 보냅니다. 여기에는 IM 채널이 구성되지 않았거나 사용자가 단순히 브라우저 기본 알림을 원하는 시나리오가 포함됩니다.
### 지원되는 이벤트
| Event | Example |
|-------|---------|
| Approval request | Agent needs permission to execute a sensitive operation |
| Goal completed | Background task finished successfully |
| Goal failed | Task encountered an unrecoverable error |
| Goal verification | Results ready for your review |
| Health alert | System detected a service disruption |
| Budget alert | Usage approaching configured limits |
| Background task done | Long-running task completed |
| System notification | Security events, pairing requests, OAuth callbacks |
### 설정
1. **설정 > 시스템 > 푸시 알림**으로 이동합니다.
2. **활성화** 전환 - 브라우저에서 알림 권한을 요청합니다.
3. 완료되었습니다. 브라우저 탭을 닫아도 알림이 도착합니다.
**테스트** 버튼을 사용하면 배송을 즉시 확인할 수 있습니다.
### 플랫폼 노트
| Platform | Support |
|----------|---------|
| Desktop browsers (Chrome, Firefox, Edge) | ✅ Full support |
| Android (Chrome, Firefox) | ✅ Full support |
| iOS / iPadOS (Safari 16.4+) | ✅ Requires "Add to Home Screen" (PWA mode) |
| Tauri desktop app | N/A — uses native OS notifications instead |
iOS에서 카드는 앱이 독립형 PWA 모드에서 실행되고 있는지 자동으로 감지하고 필요한 경우 설치 가이드를 표시합니다.
### 보안 및 유지 관리
- **VAPID 키 자동 생성** — 서버는 처음 부팅할 때 키를 생성하고 유지하며 구성은 필요하지 않습니다.
- **만료된 구독 정리** — 푸시 실패(410/404)가 발생하면 오래된 구독이 자동으로 제거됩니다.
- **타사 서비스 없음** — 푸시는 브라우저 공급업체 엔드포인트(Google FCM, Apple APN, Mozilla 자동 푸시)로 직접 이동됩니다.
- **Tauri-인식** — 기본 알림이 이미 작동하는 데스크톱 앱 빌드에서는 설정 카드가 숨겨집니다.
### 원클릭 승인 딥링크
푸시 알림을 탭하면 홈페이지뿐 아니라 정확한 채팅과 **승인 서랍**이 열립니다.
- **승인 요청**은 `/{chat_id}?approval={id}`으로 이동합니다. WebUI는 전역 ApprovalDrawer를 열고 깨끗한 URL에 대한 쿼리 매개변수를 제거합니다.
- **서비스 워커 라우팅**은 동일한 출처 경로를 삭제하고 채팅 탭이 이미 열려 있으면 포커스 전용 대신 `navigate()`을 호출합니다. 따라서 열려 있는 탭에 대한 새 승인은 여전히 서랍을 엽니다(OpenClaw의 SW는 경로 이름만 비교하고 이를 놓칩니다).
- **Chrome MCP E2E 검증** — 핫 탭 + 콜드 스타트 딥링크 경로(2026-07)
## 백그라운드 작업 자동 응답
IM 채널에서 `/btw`를 통해 백그라운드 작업을 시작하면 작업이 완료되면 결과가 자동으로 원래 대화로 다시 푸시됩니다.
- **스레드 정확도 전달** — 작업을 시작한 정확한 스레드에 응답이 도착합니다.
- **현지화된 알림** — 메시지는 사용자의 언어 기본 설정(영어, 중국어 등)을 존중합니다.
- **실패 경고** — 작업이 실패하면 무음 대신 오류 요약이 표시됩니다.
- **신뢰할 수 있는 전달** — 모든 채널 메시지와 동일한 재시도 인프라를 사용합니다.
- **무중단** — 알림 설정과 독립적으로 실행됩니다. 방송이 아닌 직접 답변입니다
Discord에서 작업을 시작하고 다른 것으로 전환한 후 다시 돌아와서 스레드에서 대기 중인 결과를 찾아보세요.
## 목표 달성 자동 응답
IM 채널에서 `/goal set`을 통해 목표를 시작하면 목표가 완료되면 완료 결과가 원래 대화로 자동으로 푸시됩니다.
- **스레드 정확도 전달** — 목표를 시작한 정확한 스레드에 응답합니다.
- **현지화된 알림** — 메시지는 목표를 만들 때 사용한 언어(영어, 중국어, 일본어, 중국어 번체)를 따릅니다.
- **딥링크 버튼** — "브라우저에서 계속"을 선택하면 WebUI의 실행 요약과 함께 전체 목표 세부정보가 열립니다.
- **성공 및 실패 범위** — 완료된 목표와 실패한 목표 모두 알림을 트리거합니다.
- **일관된 인프라** — `/btw` 백그라운드 작업 알림과 동일한 전달 파이프라인을 사용합니다.
Telegram에서 목표를 시작하고 앱을 닫은 후 몇 시간 후에 다시 돌아와 구조화된 결과를 찾으세요. 원클릭 버튼을 사용하면 브라우저에서 전체 세부정보를 볼 수 있습니다.
## 장기 작업 하트비트(제자리에서 편집)
에이전트가 출력을 보내지 않고 오랜 기간 동안 복잡한 작업을 수행하는 경우 자동으로 실시간 하트비트 메시지를 제공하므로 채팅에 여러 알림이 넘치지 않고 중단되지 않았음을 알 수 있습니다.
### 작동 방식
1. 병렬 배경 모니터는 마지막 활동(전송된 메시지, 진행률 업데이트 등) 이후의 시간을 추적합니다.
2. 2분간의 침묵 후 발신 IM 채널로 하트비트 메시지가 전송됩니다.
3. 후속 하트비트에서는 경과 시간, 걸음 수 및 단계가 업데이트되어 **동일한 메시지가 그 자리에서 편집**됩니다. 새 메시지는 생성되지 않습니다.
4. 채널이 메시지 편집을 지원하지 않는 경우 단일 메시지만 전송됩니다(스팸 없음).
5. 작업당 최대 3개의 하트비트 주기
6. NORMAL 우선순위를 사용합니다. 휴대폰에서 푸시 알림을 실행하지 않고 하트비트가 자동으로 도착합니다.
### 예시 메시지
> ⏳ 작업 — 3분(12단계, 데이터 분석)
작업이 진행됨에 따라 메시지가 업데이트됩니다.
> ⏳ 작업 — 5분(18단계, 코드 생성)
### 스마트 무음 감지
단순 간격 타이머와 달리 모니터는 **에이전트가 출력을 생성할 때마다 재설정**됩니다. 에이전트가 1분에 진행률 업데이트를 보내는 경우 해당 시점부터 2분 무음 기간이 다시 시작됩니다. 이렇게 하면 상담원이 적극적으로 통신할 때 불필요한 미리 알림을 피할 수 있습니다.
### 채널 인식 적응
하트비트는 채널이 메시지 편집(`ChannelCapabilities.edit`)을 지원하는지 여부를 자동으로 감지합니다. Telegram 및 Discord와 같은 채널은 바로 편집을 지원합니다. 단일 하트비트 메시지를 받지 않는 채널은 스팸을 방지하기 위한 추가 업데이트가 없습니다.
편집 작업이 실패하는 경우(예: 메시지가 너무 오래되어 편집할 수 없음) 시스템은 정상적으로 새 메시지 전송으로 돌아갑니다.
### 세부정보
| Aspect | Behavior |
|--------|----------|
| Silence threshold | 120 seconds (configurable via `_SILENCE_REASSURANCE_THRESHOLD`) |
| Max heartbeats | 3 per task (configurable via `_MAX_REASSURANCE_COUNT`) |
| Update mode | Edit-in-place (falls back to single send for channels without edit support) |
| Priority | NORMAL — silent delivery, no push notification |
| Language | Fully internationalized (English, Simplified Chinese, Traditional Chinese, Japanese — extensible via `.ftl` files) |
| Typing indicator | Runs in parallel — "Typing..." keeps showing during the silence window |
| Prompt cache | Zero impact — heartbeat is outbound-only, never modifies the system prompt |
| Error handling | Send/edit failures are logged silently; the main task is never interrupted |
## 채팅 내 상담원 전환
IM 채널 내에서 직접 구성된 에이전트 간에 전환하세요. 웹 UI를 열거나 구성 파일을 편집할 필요가 없습니다.
### 텔레그램(`/agent` 명령)
1. 채팅에서 `/agent`을 보내세요.
2. 사용 가능한 모든 에이전트를 나열하는 InlineKeyboard가 나타납니다. 현재 바인딩된 에이전트에는 확인 표시 표시기가 표시됩니다.
3. 원하는 에이전트를 탭하세요. 선택기 메시지가 확인 텍스트("Switched to: AgentName")로 대체됩니다.
4. 이 항목의 모든 후속 메시지는 새 에이전트(독립 시스템 프롬프트, 모델, 도구, 메모리)로 이동합니다.
### 빠른 전환 명령
구성 등록 바로 가기 명령(예: `/claude`, `/gpt`)에서 `command_bindings`을 정의하는 에이전트.
**이중 모드 라우팅:**
- `/cc fix this bug` — **원샷 라우팅**: 이 메시지는 Claude 에이전트에 의해 처리되지만 바인딩은 변경되지 않습니다. (다음 메시지는 이전 에이전트로 전달됩니다.)
- `/cc`(인수 없음) — **영구 바인딩**: 모든 후속 메시지에 대해 기본 에이전트를 Claude로 전환합니다.
이 디자인은 일시적으로 다른 에이전트가 필요할 때 앞뒤로 전환하는 데 따른 마찰을 제거합니다.
### 주제 바인딩 세분성
에이전트 바인딩은 **3계층 해결** 계층 구조를 따릅니다.
| Level | Scope | Example |
|-------|-------|---------|
| Thread | A single reply thread within a group | Different threads bound to different agents |
| Chat | A DM conversation or entire group | Default for most use cases |
| Channel | All conversations from one channel source | Fallback when no thread/chat binding exists |
### i18n 지원
모든 선택기 및 확인 메시지는 완전히 국제화되었습니다. 에이전트는 사용자의 언어 기본 설정을 자동으로 해결합니다(현재 영어 및 중국어, `.ftl` 번역 파일을 통해 확장 가능).
## 교차 장치 작업 동기화
모든 백그라운드 작업은 서버 측에 저장되며 데스크톱 앱, 웹 UI 또는 모바일 브라우저 등 연결된 클라이언트에서 액세스할 수 있습니다.
- **단일 정보 소스** — 작업 상태는 단일 장치가 아닌 서버의 Kanban 시스템에 있습니다.
- **어디서나 실시간 업데이트** — SSE 이벤트는 상태 변경(완료, 실패, 진행)을 연결된 모든 클라이언트에 동시에 푸시합니다.
- **일관된 UI** — 데스크톱(Tauri)에는 동일한 웹 UI 프런트엔드가 포함되어 있어 여러 표면에서 경험이 동일합니다.
- **IM 채널 통합** — BtwTaskNotifier는 UI 업데이트와 동시에 IM 채널에 결과를 푸시합니다.
- **IM Kanban 관리** — Telegram, Discord, Slack 등에서 직접 `/kanban`(또는 `/kb`)을 사용하여 채팅을 종료하지 않고도 작업을 생성, 나열, 편집, 완료, 차단 및 보관할 수 있습니다. LLM 비용 없음 - 명령이 에이전트 파이프라인을 완전히 우회합니다.
데스크탑에서 작업을 시작하고, 휴대폰에서 진행 상황을 확인하고, Telegram에서 `/kanban`을 통해 작업을 관리하고, Slack에서 완료 알림을 받으세요. 이 모든 것이 아무런 구성 없이 이루어집니다.
## 크로스 플랫폼 핸드오프
맥락을 잃지 않고 한 플랫폼에서 다른 플랫폼으로 대화를 전환하세요.
**두 가지 진입점:**
- **웹 UI** — 사이드바에서 대화를 마우스 오른쪽 버튼으로 클릭 → "전송 대상..." → 대화 상자에서 아이콘 및 상태 표시기를 사용하여 연결된 모든 채널을 자동 검색 → 한 번의 클릭으로 선택 및 전송
- **IM 명령** — IM 채널(Telegram, Discord, Slack 등)에 `/handoff <target_channel>`를 입력하세요.
**작동 방식:** 핸드오프는 단일 원자 DB 업데이트에서 세션 키를 대상 채널에 다시 바인딩합니다. — 밀리초의 대기 시간, 제로 데이터 복사, 전체 프롬프트 캐시 보존. 대상 키가 이미 다른 세션에서 사용되고 있는 경우 충돌을 피하기 위해 자동으로 바인딩이 해제됩니다.
**세션 정책:** `persistent`(재설정 안 함), `daily`(구성된 시간에 재설정) 또는 `idle`(비활성 후 재설정)의 세 가지 모드는 전송 후 세션 작동 방식을 제어합니다. 에이전트 신원(`agent_id`)은 전송 전반에 걸쳐 보존되므로 동일한 에이전트 성격, 도구 및 메모리가 새 채널에서 계속됩니다.
**테스트 적용 범위:** 17개의 단위 테스트 + 7개의 API 통합 테스트 = 모든 엣지 케이스(충돌 해결, 동일 채널 거부, 비활성 페어링, 에이전트 보존, 정책 모드)를 다루는 24개의 테스트입니다.
### 자동 "브라우저에서 계속" 버튼
에이전트의 모든 IM 응답에는 하단에 **"브라우저에서 계속"** 버튼이 포함되어 있습니다. 이를 탭하면 도구 호출 단계, 코드 차이점 및 파일 기록이 포함된 전체 웹 UI 대화 페이지가 한 번의 클릭으로 열립니다.
- **정확한 라우팅** — 버튼은 데이터베이스 Chat UUID(IM 플랫폼의 피어 ID 아님)를 사용하여 `/{chatUUID}`에 연결되므로 항상 올바른 대화가 열립니다.
- **백그라운드 작업 알림** — `/btw` 백그라운드 작업이 완료되면 IM 알림에도 버튼이 포함됩니다.
- **우아한 성능 저하** — 대화형 버튼을 지원하지 않는 채널(예: WeChat)은 자동으로 텍스트 링크로 대체됩니다. 공개 URL을 사용할 수 없는 경우 응답을 차단하지 않고 버튼이 자동으로 생략됩니다.
- **WebUI 필터링** — 이미 웹 UI에 있는 메시지에는 버튼이 표시되지 않습니다(중복 자체 링크 없음).
**테스트 범위:** URL 구성, DB UUID 확인, 채널 필터링, 오류 처리 및 정상적인 성능 저하를 다루는 22개 테스트(11개 단위 + 8개 통합 + 3회귀).
## 세션 연속성 및 컨텍스트 보존
IM을 통한 원격 제어는 상황을 결코 잃지 않습니다. 4개의 레이어가 원활한 연속성을 보장합니다.
| Layer | What it does |
|-------|-------------|
| **Session Strategy** | Choose Persistent (never reset), Daily (fresh each morning), or Idle (reset after N minutes of inactivity) |
| **Auto-Reset Notification** | When a session resets, the agent is told "this is a fresh conversation" and the user sees a notice — no hallucinated references to prior context |
| **History Backfill** | On cold start, the last 15 messages from the channel are automatically replayed into the session so the agent has immediate context |
| **Shared Context** | Cross-agent and cross-channel memory sharing — work started on desktop continues seamlessly when you switch to mobile IM |
전송 중에 작업 공간 컨텍스트를 잃는 메시지 전달 아키텍처(예: Coze → Claude Code)와 달리 Myrm의 에이전트는 작업 공간에서 직접 실행됩니다. 전체 파일 시스템 액세스 권한이 있고, 린터를 실행하고, git 상태를 확인하고, 프로젝트 트리를 탐색할 수 있습니다. IDE 상태 동기화 레이어가 필요하지 않습니다.
## IM에서 실행 취소, 재시도 및 파일 되돌리기
IM 채널에서 `/undo` 또는 `/retry`을 보내 에이전트의 마지막 차례를 롤백하세요(**자동 파일 복원 포함**).
| Command | What happens |
|---------|-------------|
| `/undo` | Deletes the last user + assistant message pair **and** reverts any files the agent modified during that turn |
| `/retry` | Deletes the last assistant reply, reverts its file changes, **then** re-sends your original question for a fresh answer |
**작동 방식:** 에이전트가 메시지를 처리할 때 에이전트의 SnapshotStore에서 데이터베이스까지 일관된 `message_id`이 추적됩니다. `/undo`에서 시스템은 삭제된 메시지 ID를 검색하고 해당 파일 스냅샷을 조회한 후 복원합니다. 사용자에게 현지화된 확인 메시지가 표시됩니다(예: "↩ 실행 취소: 2개의 메시지가 제거되었습니다. ↩ 3개의 파일을 되돌렸습니다.").
**중요한 이유:** 경쟁업체(OpenClaw, Hermes, DeerFlow)는 데스크톱 GUI 또는 CLI에서만 파일 되돌리기를 지원합니다. 다른 제품은 IM 채널 내의 실행 취소/재시도 명령에 연결된 파일 되돌리기를 제공하지 않습니다. 즉, 에이전트가 휴대폰에서 파일을 안전하게 편집하도록 할 수 있습니다. 문제가 발생하면 `/undo` 명령 하나로 모든 것이 해결됩니다.
## 채널 자가 치유 및 안정성
모든 채널은 상태를 지속적으로 모니터링하고 장애로부터 자동으로 복구하는 **ChannelGateway**에서 실행되며 사람의 개입이 필요하지 않습니다.
### 건강 루프
게이트웨이는 정기적인 상태 확인 주기(60초 간격)를 실행합니다. 채널이 두 번 연속 검사에 실패하면 **DEGRADED** 상태가 되고 자가 복구 파이프라인이 트리거됩니다.
1. **지수 백오프** — 재시작 지연 시간이 5초에서 최대 300초로 증가하여 리소스 스래싱을 방지합니다.
2. **지터** — 25% 무작위 변형으로 여러 채널에 동시에 장애가 발생하는 경우 천둥소리가 나는 것을 방지합니다.
3. **전체 재시작** — `stop()`(모든 핸들 해제)을 실행한 다음 `start()`(새 초기화)를 실행합니다.
4. **상태 브로드캐스트** — EventEmitter를 통해 실시간으로 프런트엔드 `ConnectionBadge` 업데이트
### 메시지 복구(InboundJournal)
충돌 기간 동안 수신된 메시지는 **손실되지 않습니다**. `InboundJournal`은 처리되기 전에 들어오는 메시지를 유지합니다. 다시 시작하면 처리되지 않은 항목이 라우팅 파이프라인을 통해 자동으로 재생되므로 사용자는 충돌이 발생한 것을 전혀 알 수 없습니다.
### 배달 못한 편지 대기열
여러 번 재시도한 후 전달에 실패한 메시지는 전체 메타데이터가 포함된 DLQ로 이동됩니다. 검사, 재시도 또는 보관이 가능하며 자동으로 사라지는 것은 없습니다.
### 일반 재연결 루프
WebSocket 기반 채널(Discord, Slack, Feishu 등)은 지수 백오프 및 지터가 있는 공통 `reconnect_loop` 유틸리티를 공유합니다. 이는 모든 장기 연결에서 일관되고 검증된 재연결 동작을 제공합니다.
### 플랫폼별 속도 제한
각 채널에는 플랫폼의 API 제한에 맞게 조정된 자체 **TokenBucket** 속도 제한기가 있습니다. WeChat 채널에는 전용 매개변수가 있습니다.
| Channel | Rate | Effect |
|---------|------|--------|
| WeChat (iLink) | 2 msg/s | Prevents personal account throttling |
| WeChat Official | 1 msg/s | Respects Official Account API quotas |
플랫폼이 속도 제한 오류(예: WeChat errcode 45011/45015/45047 또는 iLink errcode -2)를 반환하면 시스템은 다음을 수행합니다.
1. 플랫폼별 `retry_after` 지연을 사용하여 오류를 `RateLimitError`에 매핑합니다.
2. `retry_after` 값을 고려하여 지수 백오프로 재시도
3. 모든 재시도가 소진되면 DLQ로 폴백합니다. 문자 메시지는 자동으로 삭제되지 않습니다.
### 회로 차단기 및 우아한 성능 저하
채널의 아웃바운드 API에 반복적인 오류가 발생하면 두 개의 보완적인 보호 계층이 활성화됩니다.
**채널 수준 회로 차단기** — 5회 연속 전송 실패 후 회로가 트립되고 30초 동안 아웃바운드 디스패치를 일시 중지합니다. 메시지는 PriorityQueue(최대 256개)에 안전하게 대기하고 회로가 닫히면 전달됩니다. 이는 성능이 저하된 플랫폼 API의 범람을 방지합니다.
**스트리밍 단계적 성능 저하** — 라이브 스트리밍 업데이트(예: 실시간 메시지 편집) 중에 오류가 발생하면 강제 중지 대신 5단계 점진적인 속도 저하가 발생합니다.
| Level | Multiplier | Effect |
|-------|-----------|--------|
| NORMAL | 1× | Standard update frequency |
| DEGRADED_1 | 2× | Slightly slower updates |
| DEGRADED_2 | 4× | Noticeable delay, still responsive |
| DEGRADED_3 | 8× | Significant delay |
| DEGRADED_4 | 16× | Maximum slowdown, updates still delivered |
핵심 원칙: **사용자는 항상 업데이트를 받습니다** — 성능 저하 중에는 느리게 도착할 수 있지만 완전히 멈추지는 않습니다. 이는 피드백이 전혀 없는 갑작스러운 30초 정전 기간을 생성하는 기존 회로 차단기보다 우수합니다.
### 이것이 사용자에게 미치는 영향
- **다운타임 제로 경험** — 일시적인 네트워크 문제 또는 플랫폼 중단이 스스로 해결됩니다.
- **메시지 손실 없음** — 서버가 충돌하더라도 재시작 시 대기 중인 메시지가 복구됩니다.
- **계정 금지 없음** — 채널당 속도 제한으로 플랫폼 API 할당량 초과를 방지합니다.
- **표시 상태** — 채널 상태는 색상으로 구분된 배지를 통해 설정 > 채널에서 항상 표시됩니다.
- **수동으로 다시 시작하지 않음** — 채널이 스스로 치유됩니다. 결과만 볼 뿐 회복 과정은 볼 수 없습니다
- **갑자기 정전 없음** — 스트리밍 업데이트가 갑자기 중지되는 대신 정상적으로 저하됩니다.
## GitHub 채널 및 CI/CD 통합
**GitHub 채널**은 에이전트를 저장소 이벤트를 수신하고 PR 댓글로 응답하는 자동화된 코드 검토자로 전환합니다.
### 지원되는 이벤트
| Event | Trigger | Agent Action |
|-------|---------|-------------|
| `pull_request` | PR opened / updated | Automatic code review + comment |
| `issues` | Issue created / updated | Triage, labeling, response |
| `issue_comment` | New comment on Issue/PR | Contextual reply |
| `push` | Commits pushed | Change analysis |
| `pull_request_review` | Review submitted | Follow-up discussion |
### 설정
1. **설정 > 채널 > GitHub**으로 이동합니다.
2. **개인 액세스 토큰**(댓글 게시 범위는 `repo`)을 입력하세요.
3. **Webhook 비밀번호**를 입력하세요(서명 확인용).
4. GitHub 저장소 설정에 웹훅 URL(`https://your-server/channels/github/webhook`)을 추가하세요.
### 보안
모든 수신 웹훅은 **X-Hub-Signature-256**(HMAC-SHA256)을 사용하여 확인됩니다. 잘못된 서명은 401 응답으로 거부됩니다.
### CI/CD 파이프라인 통합
GitHub 외에도 모든 CI/CD 플랫폼(Jenkins, GitLab CI, 云效, CodePipeline)은 REST API을 통해 에이전트를 트리거할 수 있습니다.```bash
curl -X POST https://your-server/api/chats/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "Review the latest commit on branch feature/xyz"}'