diff --git a/communication/api.mdx b/communication/api.mdx new file mode 100644 index 000000000..b86e23fb2 --- /dev/null +++ b/communication/api.mdx @@ -0,0 +1,190 @@ +--- +title: "API messages" +description: "Talk to your assistant from your own code" +--- + +Every other channel puts a person at one end — a phone, an inbox, a chat +window. This one puts your code there instead. Send your assistant a message +with an HTTP request, poll for its reply, and wire it into whatever you're +building. No browser, no phone number, no connected account — just your API +key. + +It's the same assistant either way. Something you ask for over the API is +something you can follow up on in [Chat](/communication/console-chat) an hour +later, and it'll know what you mean. + +## What you need + +- **Your API key** and **your assistant's ID**, both from the + [Console](https://console.unify.ai). +- The base URL: `https://api.unify.ai/v0` +- A Bearer token header on every request: + +``` +Authorization: Bearer YOUR_API_KEY +``` + + + Assistants running in a [local deployment](/local-deployment/overview) don't + receive API messages — this channel is for assistants hosted by Unify. + + +## Sending a message + +`POST /messages` with the assistant's ID and your message: + +```bash +curl -X POST https://api.unify.ai/v0/messages \ + -H "Authorization: Bearer $UNIFY_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistant_id": , + "message": "Add milk to my shopping list." + }' +``` + +You get back a `message_id` straight away, before your assistant has done +anything with it: + +```json +{ + "info": { + "message_id": "msg_abc123", + "assistant_id": 42, + "message": "Add milk to my shopping list.", + "status": "processing", + "response": null, + "tags": [], + "attachments": [], + "response_tags": null, + "response_attachments": null, + "created_at": "2026-08-10T12:00:00Z", + "completed_at": null + } +} +``` + +## Polling for the reply + +Your assistant works on the message in the background — it might answer in a +second, or go off and actually do the thing first. Poll +`GET /messages/{message_id}` until `status` flips from `processing` to +`completed`: + +```bash +curl https://api.unify.ai/v0/messages/msg_abc123 \ + -H "Authorization: Bearer $UNIFY_KEY" +``` + +```json +{ + "info": { + "message_id": "msg_abc123", + "assistant_id": 42, + "message": "Add milk to my shopping list.", + "status": "completed", + "response": "Done! I've added milk to your shopping list.", + "tags": [], + "attachments": [], + "response_tags": [], + "response_attachments": null, + "created_at": "2026-08-10T12:00:00Z", + "completed_at": "2026-08-10T12:00:05Z" + } +} +``` + +`response` can come back `null` on a completed message. That's not an error — +your assistant decides whether a reply is warranted, the same way it does on +any other channel, and sometimes doing the task quietly is the right answer. + +## From Python + +The SDK wraps both calls: + +```python +import unisdk + +status = unisdk.agent.send_message( + assistant_id=, + message="Add milk to my shopping list.", +) + +status = unisdk.agent.get_message_status(status["message_id"]) +print(status["status"], status["response"]) +``` + +## Sending files + +Upload each file first, then reference it in the message. + + + + ```bash + curl -X POST https://api.unify.ai/v0/messages/attachments \ + -H "Authorization: Bearer $UNIFY_KEY" \ + -F "file=@report.pdf" \ + -F "assistant_id=" + ``` + + You get back the file's metadata: + + ```json + { + "id": "att_xyz789", + "filename": "report.pdf", + "gs_url": "gs://bucket/path/report.pdf", + "content_type": "application/pdf", + "size_bytes": 204800 + } + ``` + + + ```bash + curl -X POST https://api.unify.ai/v0/messages \ + -H "Authorization: Bearer $UNIFY_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistant_id": , + "message": "Please summarise this report.", + "attachments": [ + { + "id": "att_xyz789", + "filename": "report.pdf", + "gs_url": "gs://bucket/path/report.pdf" + } + ] + }' + ``` + + + +Files are capped at **25 MB** each. Your assistant can send files back too — +they arrive as `response_attachments` on the completed message, each with a +download URL. + +## Tags + +Tags are arbitrary strings you can hang off a message. Your assistant treats +them as opaque routing labels — it doesn't read anything into them — and +echoes them back on its reply as `response_tags`. + +```bash +curl -X POST https://api.unify.ai/v0/messages \ + -H "Authorization: Bearer $UNIFY_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistant_id": , + "message": "Summarise today'\''s sales figures.", + "tags": ["source:slack", "channel:#analytics"] + }' +``` + +That's what makes them useful for bridging: if you're relaying messages from +somewhere else, tag the inbound message with wherever it came from and the +reply tells you where to send it back. + + + Tags are how you keep one assistant serving several surfaces at once without + losing track of which reply belongs to which request. + diff --git a/communication/behavior.mdx b/communication/behavior.mdx index 5a44c0ddd..d2c677c06 100644 --- a/communication/behavior.mdx +++ b/communication/behavior.mdx @@ -20,6 +20,14 @@ It won't send you play-by-play updates unless you want them, and in group settings — Slack channels, meetings, calls with several people — it speaks when addressed or when it genuinely has something to add. +In a room with several AI teammates — a [group or team +chat](/communication/group-chats), a Slack or Teams channel — exactly one of +them should answer any given message. Name the teammate you want and the +rest stay out of it; name nobody and whoever the work belongs to picks it +up. Assistants also mostly don't reply to *each other*: acknowledging a +teammate is noise, and two assistants trading acknowledgements is a loop +that costs real money. + ## It can reach out first Your assistant isn't purely reactive: @@ -28,10 +36,11 @@ Your assistant isn't purely reactive: tells you on an appropriate channel. - **Scheduled work** — [tasks](/tasks/overview) you've scheduled can end with a message, an email, or a call at the time you chose. -- **Gentle follow-ups** — if a conversation with your T-W1N goes quiet while - something needs your input, it may send a friendly follow-up email. This - re-engagement is specific to your T-W1N; hired teammates don't do it. Ask it - to stop and it stops. +- **Gentle follow-ups** — if you've been away from the platform for a while, + your T-W1N sends a short check-in email. At most three per quiet spell, and + then it leaves you alone until you're active again. This re-engagement is + specific to your T-W1N; hired teammates don't do it. Ask it to stop and it + stops, until you ask it to resume. - **Ringing you** — when a live conversation beats a wall of text, it can ring you on [Unify Meet](/communication/unify-meet), and falls back to chat if you don't pick up. diff --git a/communication/console-chat.mdx b/communication/console-chat.mdx index fd920d119..2ce783dec 100644 --- a/communication/console-chat.mdx +++ b/communication/console-chat.mdx @@ -56,6 +56,13 @@ brings you back to now. For history *beyond* this one thread — email, SMS, WhatsApp, and every other channel — see [Transcripts](/communication/recordings-and-transcripts). +## Beyond your own thread + +This page is your one-to-one thread with one assistant. In an organization +the same composer also runs [group chats](/communication/group-chats) — +rooms shared with colleagues, teams, and several assistants at once, where +naming the teammate you want decides who answers. + ## Always on, and honest when it isn't Chat is your assistant's home channel: updates, links, and deliverables diff --git a/communication/developers/conversation-manager.mdx b/communication/developers/conversation-manager.mdx index 60eb24ea9..50758aaac 100644 --- a/communication/developers/conversation-manager.mdx +++ b/communication/developers/conversation-manager.mdx @@ -32,8 +32,7 @@ plus call-lifecycle events (`PhoneCallReceived`, `PhoneCallAnswered`, `PhoneCallEnded`, `UnifyMeetStarted`…), per-utterance voice events (`InboundPhoneUtterance`, `OutboundUnifyMeetUtterance`…), reactions, voice-control events (`FastBrainNotification`, `VoiceInterrupt`), and -lifecycle events (`StartupEvent`, `TaskDue`, `InactivityFollowup`, -`PreHireMessage`). +lifecycle events (`StartupEvent`, `TaskDue`, `PreHireMessage`). Two mapping layers connect the world to handlers: @@ -56,7 +55,7 @@ Two mapping layers connect the world to handlers: defines the `Medium` enum — the single source of truth for channel types (`UNIFY_MESSAGE`, `EMAIL`, `SMS_MESSAGE`, `WHATSAPP_MESSAGE`, `WHATSAPP_CALL`, `PHONE_CALL`, `UNIFY_MEET`, `GOOGLE_MEET`, `TEAMS_MEET`, -Slack/Discord variants, and both the delegated-Graph +`API_MESSAGE`, Slack/Discord variants, and both the delegated-Graph (`TEAMS_MESSAGE`, `TEAMS_CHANNEL_MESSAGE`) and org-installed bot (`MS_TEAMS_BOT_MESSAGE`, `MS_TEAMS_BOT_CHANNEL_MESSAGE`) Teams mediums…). The two org-installed bot send tools are gated behind the assistant's @@ -121,9 +120,8 @@ concern: | [`renderer.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/renderer.py) | State → prompt snapshots and diffs | | [`contact_index.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/contact_index.py) | Live per-medium message threads | | [`notifications.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/notifications.py) | The `NotificationBar` surfaced in prompts | -| [`task_activation.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/task_activation.py) | `TaskDue` wake-ups and live task execution | -| [`inactivity.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/inactivity.py) | Re-engagement follow-ups | -| [`proactive_speech.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/proactive_speech.py) / [`speech_urgency.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/speech_urgency.py) | Breaking silence on calls / preempting the slow brain for urgent speech | +| [`task_execution.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/task_execution.py) | `TaskDue` wake-ups and live task execution | +| [`proactive_speech.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/proactive_speech.py) | Breaking silence on calls | | [`comms_utils.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/comms_utils.py) | HTTP calls to the gateway's channel endpoints | | [`managers_utils.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/managers_utils.py) | Manager init and `log_message()` → transcripts | @@ -154,6 +152,32 @@ Outbound events published by the brain's own sends set `suppress_slow_brain_wake` so the assistant isn't re-woken by its own confirmations. +### The API message round trip + +The [developer API channel](/communication/api) is the one send path that +doesn't originate a conversation — it completes a caller that is already +waiting, so it runs request/response rather than fire-and-forget: + +1. **Inbound.** Orchestra's `POST /v0/messages` persists an `ApiMessage` + row and dispatches it to the adapters, which publish an `api_message` + envelope. `CommsManager.events_map` maps that thread to + `ApiMessageReceived`, whose handler parks the `api_message_id` and the + caller's tags on the `ConversationManager` as + `_pending_api_message_id` / `_pending_api_message_tags`. +2. **Outbound.** `send_api_response` reads that pending id, so it is only + meaningful while a call is in flight — with nothing pending it returns + `{"status": "ok", "note": "no pending api message"}` rather than opening + a new outbound conversation. It uploads any attachments, then + `comms_utils.complete_api_message()` issues + `PUT {ORCHESTRA_URL}/messages/{id}/complete`, which is what flips the + caller's poll from `processing` to `completed`. +3. **Record.** An `api_message_sent` event writes the transcript row, + anchored to the boss contact — the API exchange lands in the same + durable history as every other medium (`Medium.API_MESSAGE`). + +Tags are opaque to the runtime; the prompt tells the brain to echo them +back by default so the developer can route the reply on their own side. + ## Transcripts [`unify/transcript_manager/transcript_manager.py`](https://github.com/unifyai/unify/blob/main/unify/transcript_manager/transcript_manager.py) @@ -175,8 +199,13 @@ machinery](https://github.com/unifyai/unify/blob/main/unify/conversation_manager in two directions. Downward: every in-flight `act(...)` is a steerable handle the brain can `ask`, `interject`, `pause`, `resume`, or `stop` via dynamically generated tools. Upward: when a user speaks while the slow -brain is mid-turn, `SpeechUrgencyEvaluator` -([`domains/speech_urgency.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/speech_urgency.py)) -classifies the utterance and may cancel the running turn so the new input -takes priority — the runtime-level implementation of "you can always -interrupt." +brain is mid-turn, the input does **not** cancel the running turn. The +`Debouncer` +([`domains/utils.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/utils.py)) +holds one running turn plus at most one pending turn — a new submission +replaces whatever was pending and starts when the current turn finishes. +Preemption used to exist (a `SpeechUrgencyEvaluator` that classified the +utterance and cancelled the running turn) and was removed: the queue of two +is the whole mechanism. What makes interruption feel immediate on a call is +the fast brain — barge-in and the interim turn — not turn cancellation; see +[Voice calls](/communication/developers/voice). diff --git a/communication/developers/voice.mdx b/communication/developers/voice.mdx index 9b5e718b4..f3079d4aa 100644 --- a/communication/developers/voice.mdx +++ b/communication/developers/voice.mdx @@ -71,25 +71,44 @@ browser automation rather than SIP. records the `spoken_prefix` actually delivered and the `unheard_remainder`, so the slow brain knows exactly what the user did and didn't hear and can re-weave the rest. -- **Urgency preemption.** If the user says something urgent while the slow - brain is mid-turn, `SpeechUrgencyEvaluator` - ([`domains/speech_urgency.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/speech_urgency.py)) - can cancel the running turn in favor of the new input. +- **No turn preemption.** Speaking mid-turn does not cancel the running + slow-brain turn. The new input queues as the single pending turn (see + [the conversation runtime](/communication/developers/conversation-manager)), + and the fast brain covers the gap. Urgency-based preemption was tried and + removed. - **Proactive speech.** During long silences while work runs, `ProactiveSpeech` ([`domains/proactive_speech.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/proactive_speech.py)) decides whether the assistant should say something unprompted. -## Speakers and enrollment - -Diarized speakers who aren't engaged contacts are transcribed as context -but don't get replies; the slow brain's `engage_speaker` / -`disengage_speaker` tools flip that, mirrored in the call manager's -engagement state. Voice profiles (`VoiceEnrollmentCaptured`, -`VoiceEnrollmentSuggested`, and `speaker_id.SpeakerTracker` in -[`medium_scripts/`](https://github.com/unifyai/unify/tree/main/unify/conversation_manager/medium_scripts)) -let known voices be pinned across calls — enrolled embeddings ride along -in the dispatch metadata. +## Who said what + +Attribution comes from the meeting roster and the platform's own +participant signals — never from matching voices. + +In a browser meeting the two halves arrive separately: the transcriber +tags each finalised utterance with an anonymous diarization id (`S0`, +`S1`), while the meeting platform reports spans of who was speaking over +the Recall relay. +[`meet_speaker_map.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/meet_speaker_map.py) +pairs them by **overlap of time spans** rather than by sampling who is +speaking when a final lands — by then the speaker has stopped and the +platform has already sent `speech_off`, so instantaneous sampling fires +only when someone talks over the previous speaker's tail, exactly when +it's most likely to name the wrong person. Votes accumulate rather than +binding on first sight, because diarization ids are per-call and drift. +Elsewhere, an unresolved turn is attributed to the call contact and the +slow brain infers the real speaker from the conversation. + +Enrolled voice embeddings are **not** compared against live audio to +decide who is speaking. That path was removed after production audio +showed the cosines conflated distinct speakers — including the +assistant's own TTS voice — about as often as they separated them, so a +matched label was as likely to be wrong as right. `SpeakerTracker` +([`speaker_id.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/speaker_id.py)) +remains as capture-only machinery: clustering keeps auto-enrollment +single-voice pure and counts distinct voices behind +`VoiceEnrollmentCaptured` / `VoiceEnrollmentSuggested`. ## Hang-up semantics diff --git a/communication/email.mdx b/communication/email.mdx index 533f691da..278b0c379 100644 --- a/communication/email.mdx +++ b/communication/email.mdx @@ -8,10 +8,15 @@ threads, handling attachments, and looping in cc'd colleagues, just like any teammate. - **If this is your T-W1N** (your digital twin): its email is platform-managed - and already set up — there's nothing to create or configure. T-W1N acts on - *your* behalf, so it uses your own connected account rather than a mailbox of - its own. The setup below is for **hired teammates**. + **If this is your T-W1N** (your digital twin): its address is + platform-managed and already set up — there's nothing to create or + configure. T-W1N's address is shared across the platform, and mail you send + to it reaches *your* T-W1N because your own contact details are + [verified](/communication/setup) — which is why verifying them matters. + + That's separate from T-W1N working inside **your** mailbox through your + [workspace connection](/workspace/email): mail it sends from there goes out + as you, from your account. The setup below is for **hired teammates**. ## How your assistant gets an email address @@ -61,9 +66,10 @@ unlocks calendar, files, contacts, and tasks, depending on what you grant. ## Email in the flow of work Email is your assistant's channel of choice for anything long-form: reports, -summaries, documents. It's also how your assistant gently follows up if you've -gone quiet on something that needs your input — and if you'd rather it didn't, -just tell it to stop the follow-ups. +summaries, documents. It's also where your [T-W1N checks +in](/communication/behavior) if you've been away from the platform for a +while — those come from your T-W1N rather than a hired teammate, and stop as +soon as you ask. You don't have to manage the mailbox. Your assistant watches its inbox and diff --git a/communication/group-chats.mdx b/communication/group-chats.mdx new file mode 100644 index 000000000..582dc1c58 --- /dev/null +++ b/communication/group-chats.mdx @@ -0,0 +1,72 @@ +--- +title: "Group chats" +description: "Team rooms, ad-hoc groups, and DMs with colleagues" +--- + +[Console chat](/communication/console-chat) is a thread between you and one +assistant. It isn't the only thread you get. In an organization, the +assistant list is a full roster — your **teams**, your human **colleagues**, +and your **assistants** — and any of them opens a conversation. + +Rooms work like chat with one difference that changes how they feel: several +AI teammates can be listening at once, so *who answers* is a real question. + + + Colleague DMs and groups exist inside an **organization**. On a personal + account, the roster is just your own assistants. + + +## Three kinds of room + +- **Colleague DMs** — pick a person from **Real** in the roster for a + one-to-one thread with them, presence dot and all. No assistant is + listening to a human DM; it's just the two of you. +- **Groups** — an ad-hoc room you create with any mix of colleagues and + assistants, optionally named. You can add and remove members later. +- **Team chats** — one shared thread per [team](/teams/overview), with every + member in it, human and AI. + +## Who answers + +Every message in a team or group room is delivered to **every** AI teammate +in that room — not just the one you had in mind. They're told to work out +whose turn it is rather than all pile in: + +- **Name someone** and it's theirs. Type `@` for a picker, or just type the + name — a hand-typed `@Ada` addresses Ada exactly as much as a picked one. +- **Name a teammate other than the one you'd expect** and the others stay + quiet, even when they could have answered. Talking over a named teammate is + worse than saying nothing. +- **Name nobody** and the best-placed teammate takes it — the one whose work + it's plainly about. This is the case where you might get silence, so name + someone if it matters. + +Your personal T-W1N stays out of team and group rooms. Its job is your own +thread, not the room. + + + Rooms have a brake on assistants talking to each other: after **three** + consecutive assistant messages with no human turn, the room stops waking + assistants until a person says something. If a room goes quiet mid-exchange + between two assistants, that's why — say anything and it resumes. + + +## Calls + +Any room can become a call, not just your 1:1 with an assistant. The call +button rings everyone in the room; people answer, decline, or join late, and +assistants are dispatched into the same call. It's the same machinery as +[Unify Meet](/communication/unify-meet) — one call surface across colleague +DMs, groups, teams, and assistant threads. + +## The composer + +Rooms use the same composer as [Console chat](/communication/console-chat): +attachments, voice notes transcribed into the box, camera capture, emoji +reactions, and a search over the room's history. + + + A group is the quickest way to get two assistants working the same problem + in front of you — put both in a room with the colleague who owns the work, + and name whichever one you want to pick up each turn. + diff --git a/communication/microsoft-teams.mdx b/communication/microsoft-teams.mdx index 50e378f95..fb6d7837f 100644 --- a/communication/microsoft-teams.mdx +++ b/communication/microsoft-teams.mdx @@ -21,13 +21,13 @@ Unify bot, not as a person. ## Setup A Microsoft admin installs the **Unify Teams app** into your organization's -Teams. Once it's installed, every assistant in the org — and your coordinator -— is reachable through it; there's nothing to configure per assistant. +Teams. Once it's installed, every assistant in the org — and your T-W1N — is +reachable through it; there's nothing to configure per assistant. ## Messaging -- **1:1 chat** — message the Unify app in Teams and your coordinator picks up - the conversation. +- **1:1 chat** — message the Unify app in Teams and your T-W1N, the + coordinator that fields anything unaddressed, picks up the conversation. - **Group chats** — add the app to a group chat and @mention it to bring it in; it replies in the same conversation. - **Channels** — @mention the app in a channel and it replies in the thread, @@ -39,10 +39,10 @@ Because the app is shared, addressing works like Slack: - In a **channel or group chat**, @mention the app and include the teammate's name to reach a specific assistant (for example, `@Unify Alex, can you…`). - @mention it with no name and the message goes to your **coordinator**, who - can hand off from there. -- In a **1:1 chat**, messages go to your coordinator — there's no name to add, - so naming a teammate isn't used here. + @mention it with no name and the message goes to your **T-W1N**, who can + hand off from there. +- In a **1:1 chat**, messages go to your T-W1N — there's no name to add, so + naming a teammate isn't used here. Teams only delivers channel and group-chat messages to the app when it's diff --git a/communication/overview.mdx b/communication/overview.mdx index 4ab369fd9..889b45efb 100644 --- a/communication/overview.mdx +++ b/communication/overview.mdx @@ -14,6 +14,7 @@ assistant with the same memory of everything you've discussed. | Channel | You → Assistant | Assistant → You | Setup needed | |---|---|---|---| | [Console chat](/communication/console-chat) | Yes | Yes | None — works immediately | +| [Group chats](/communication/group-chats) (teams, groups, colleagues) | Yes | Yes | None — organization accounts | | [Unify Meet](/communication/unify-meet) (browser calls) | Yes | Yes — it can ring you | None — works immediately | | [Phone calls](/communication/phone-calls) | Yes | Yes | Assistant phone number | | [SMS](/communication/sms) | Yes | Yes | Assistant phone number | @@ -22,6 +23,7 @@ assistant with the same memory of everything you've discussed. | [Slack](/communication/slack) | Yes | Yes | Slack app install | | [Microsoft Teams](/communication/microsoft-teams) | Yes | Yes | Teams app install ([or Microsoft 365 connection](/workspace/teams)) | | [Discord](/communication/discord) | Yes | Yes | Discord ID on your profile | +| [API](/communication/api) | Yes — from your own code | Yes — it replies to your call | API key | | [Google Meet & Teams meetings](/workspace/meetings) | Invite it to a meeting | It can create Teams meetings | Meeting link | ## Two channels work out of the box @@ -34,8 +36,10 @@ minutes of one-time setup. ## Setting up the other channels -Setup follows the same pattern for every channel, and is covered in detail in -[Setting up channels](/communication/setup): +Setup follows the same pattern for every channel your assistant talks to +people on, and is covered in detail in +[Setting up channels](/communication/setup). ([API messages](/communication/api) +are the exception — no contact details, just your API key.) @@ -75,8 +79,9 @@ A few things that hold everywhere: WhatsApp, and preferences. - **It respects boundaries.** People can be marked as do-not-contact, and your assistant will never message them. -- **It can follow up.** If a conversation goes quiet, your assistant may send a - friendly follow-up email. You can opt out any time by asking it to stop. +- **Your T-W1N checks in.** If you've been away from the platform for a while, + your T-W1N sends a short check-in email — a few at most, and only ever from + your T-W1N, never a hired teammate. Ask it to stop and it stops. ## What's in this section @@ -84,6 +89,9 @@ A few things that hold everywhere: Text chat with file attachments, reactions, and voice input. + + Team rooms, ad-hoc groups, and DMs with colleagues. + Browser voice & video calls with two-way screen sharing. @@ -108,6 +116,9 @@ A few things that hold everywhere: DMs and server channels. + + Message it from your own code and poll for the reply. + } href="/workspace/meetings"> Your assistant joins Google Meet and Teams meetings. diff --git a/communication/phone-calls.mdx b/communication/phone-calls.mdx index 9eb401165..1412a457c 100644 --- a/communication/phone-calls.mdx +++ b/communication/phone-calls.mdx @@ -31,9 +31,13 @@ Australia, Canada, Finland, Netherlands, Puerto Rico, Thailand, and Poland**. Dial its number from your phone. Your assistant picks up and talks with you naturally — same voice, same memory, same colleague you know from chat. -Calls to the assistant are for **known contacts**. If someone the assistant -doesn't know calls the number, they hear a short message directing them to the -Console instead of reaching your assistant. +Calls are for people your assistant knows. On the shared numbers T-W1N uses, +a caller it doesn't recognize never gets through — they hear a short message +directing them to the Console. On an assistant's own number the call does +reach the assistant, but an unknown caller isn't treated as a known contact: +they're recorded as a [contact](/communication/contacts) with responses +switched off, and your assistant comes to you for guidance rather than acting +on what a stranger asked for. ## Your assistant calling you (or others) diff --git a/communication/recordings-and-transcripts.mdx b/communication/recordings-and-transcripts.mdx index e175e0d64..7cb74c56a 100644 --- a/communication/recordings-and-transcripts.mdx +++ b/communication/recordings-and-transcripts.mdx @@ -22,7 +22,10 @@ between you and your assistant, Transcripts is the historian's view of **Chat**, **Email**, **Call**, **SMS**, **WhatsApp**, **Slack**, **Discord** — or **All** for the full stream. Calls of every kind (Unify Meet, phone, WhatsApp calls, Google Meet, Teams meetings) are - gathered under **Call**. + gathered under **Call**. Channels without a rail entry of their own — + [Microsoft Teams](/communication/microsoft-teams) messages and + [API messages](/communication/api) — are in the record too; find them + under **All**. - **Switch layout.** **Threads** mode groups the record into conversations — an email thread, a call, an SMS exchange — each showing its subject, channel, message count, and participants. **Feed** mode is diff --git a/communication/setup.mdx b/communication/setup.mdx index 17a3e916d..b2876606a 100644 --- a/communication/setup.mdx +++ b/communication/setup.mdx @@ -52,6 +52,20 @@ From there: Add Discord and your assistant gets a bot identity that can DM you and join your servers. See [Discord](/communication/discord). + + Choose **Add to Slack** and authorize the Unify app. You connect a + workspace **once** for the whole account or organization — every + assistant becomes reachable through it, and you address a specific one + by naming it in the mention. Only the account owner, or an org owner or + admin, can connect it. See [Slack](/communication/slack). + + + Nothing to create per assistant — a Microsoft admin installs the Unify + Teams app once for the organization and every assistant is reachable + through it. See [Microsoft Teams](/communication/microsoft-teams). (An + assistant can also act through its *own* Microsoft 365 account instead; + that's part of the [workspace connection](/workspace/teams).) + @@ -72,6 +86,7 @@ senders are registered), which are paid in credits from your wallet: | WhatsApp | Yes | Yes | | Discord | Yes | Yes | | Email | Free | Free | +| Slack & Microsoft Teams | Free | Free | | Console chat & Unify Meet | Free | Free | Exact amounts vary by channel and country, and are always shown in the diff --git a/communication/slack.mdx b/communication/slack.mdx index 4b794c4a0..d1fbc9b45 100644 --- a/communication/slack.mdx +++ b/communication/slack.mdx @@ -1,30 +1,68 @@ --- title: "Slack" -description: "Bring your assistant into your Slack workspace" +description: "Reach your assistants from your Slack workspace" --- -Add your assistant to Slack and it becomes a member of your workspace you can -DM, @mention, and collaborate with in channels. +The **Unify Slack app** brings your assistants into Slack — DMs, channels, +and threads. It's installed once for your account or organization, and every +assistant becomes reachable through it. Like the [Teams +app](/communication/microsoft-teams), your assistants speak as the shared +Unify app rather than as separate Slack members, so addressing works by +naming the teammate you want. ## Setup -Connect Slack from the Console — your assistant can open the setup flow for -you, or you'll find it under your assistant's **Contact Details → Slack**. -A workspace admin approves the Unify Slack app, and your assistant appears in -your workspace. +Open your assistant's **Contact Details → Slack** and choose **Add to +Slack**. You connect a workspace once — every assistant on the account (or +in the organization) becomes reachable through it, with nothing to configure +per assistant. + + + Only the account owner, or an organization owner or admin, can connect the + workspace. If you're not one of them, the Slack tab tells you who to ask. + + +## Reaching a specific teammate + +Mention the app and include the teammate's name: + +``` +@Unify Alex, can you pull yesterday's numbers? +``` + +From there, the conversation sticks: + +- **In a channel**, naming a teammate hands them the thread. Replies in that + thread reach the same assistant without naming them again. +- **In a DM** with the app, the first message goes to your **T-W1N**, the + coordinator that fields anything unaddressed. Name a teammate in the DM and + the conversation is pinned to them from then on. +- **If the name doesn't match** anyone — or matches more than one teammate — + your T-W1N takes the thread and sorts it out in place rather than guessing. + + + In a channel, a message that names nobody and isn't part of an established + thread reaches **no one**. Name the teammate you want on the first message; + after that the thread carries the routing. + + +A thread or DM that goes quiet for two weeks forgets which assistant it +belonged to. Name the teammate again and it picks straight back up. ## What you can do -- **Direct messages** — DM your assistant for the same one-on-one - conversation you'd have anywhere else. -- **Channel mentions** — @mention your assistant in a channel and it joins - the discussion. It replies in-thread, keeping channels tidy. +- **Direct messages** — the same one-on-one conversation you'd have anywhere + else, with your T-W1N or with any teammate you've named. +- **Channel threads** — mention the app in a channel and it replies in + thread, keeping the channel tidy. Invite the app to the channel first. - **File attachments** — share files in Slack and your assistant picks them up and works with them. ## Good to know -- Your assistant only speaks in a channel when it's mentioned or directly - relevant — it won't spam your team's conversations. +- Your assistant only speaks when it's addressed — it won't spam your team's + conversations. +- Coordinators are personal. In an organization, each member's unaddressed + messages go to *their own* T-W1N, not to a shared one. - It's the same assistant across every surface: a task you discussed in Slack can be delivered over email, and vice versa. diff --git a/communication/sms.mdx b/communication/sms.mdx index fc06580bd..b7a15b950 100644 --- a/communication/sms.mdx +++ b/communication/sms.mdx @@ -28,6 +28,9 @@ text it. If not, see [Setting up channels](/communication/setup). - SMS is **text only** — for photos, documents, and voice notes, use [WhatsApp](/communication/whatsapp) or [email](/communication/email) instead. -- Like calls, SMS works between your assistant and its **known contacts**. - Strangers texting the number get a polite pointer to the Console rather - than a conversation. +- Like calls, SMS is for people your assistant **knows**. A text to one of + T-W1N's shared numbers from an unrecognized number gets an automated reply + rather than a conversation. On an assistant's own number the text reaches + it, but the sender lands as a [contact](/communication/contacts) with + responses switched off — your assistant tells you about them and asks how + to handle it instead of replying. diff --git a/communication/unify-meet.mdx b/communication/unify-meet.mdx index f4e360f2e..90e04e568 100644 --- a/communication/unify-meet.mdx +++ b/communication/unify-meet.mdx @@ -70,3 +70,6 @@ This is where Unify Meet really shines: conversation uninvited. - **One call at a time.** Your assistant holds one live voice conversation at a time — if you're on a Meet call, it won't simultaneously be on the phone. +- **Not only one-to-one.** The same call surface runs across + [rooms](/communication/group-chats): ring a colleague, a group, or a whole + team, and the room's assistants join the call with everyone else. diff --git a/mint.json b/mint.json index 1668e868e..87400cb38 100644 --- a/mint.json +++ b/mint.json @@ -48,6 +48,7 @@ "pages": [ "communication/overview", "communication/console-chat", + "communication/group-chats", "communication/unify-meet", "communication/phone-calls", "communication/sms", @@ -56,6 +57,7 @@ "communication/slack", "communication/microsoft-teams", "communication/discord", + "communication/api", "communication/setup", "communication/voice", "communication/behavior",