How AddConvAG turns an off-platform thread into a unique z-link deal room without minting an offer
Ticket: ZLY-1866. Parent: ZLY-1858.
The talent already has a thread outside Z — email, DM, a half-written deal. They should not have to ask the brand to start over. Bring a conversation to Z opens a deal room on the current agent, seeds what we learned, and gives the brand a unique link. The brand (often not logged in, maybe with no account) first sees a welcome, then signs up, then lands in that same room as regular z-link chat.
AddConvAG is a real agent in the ops catalog (add-conversation, kind intake) at
/admin/z-agent?tab=ops. It is not a room persona. It never talks to the
brand. After the room exists, the brand talks to the usual host-facing
persona. AddConvAG must not mint an offer.
This is not Test agent (a demo rehearsal) and
not a bare /z/:slug visit (a new inbound from a stranger).
Entry: Conversations + (desktop, mobile, empty inbox). Agency-wide roster inbox has no + — there is no single “this agent”. When the agency is acting as a talent, the + belongs to that talent.
Breadcrumb: Conversations → New. Page title: Bring a conversation to Z. One box: paste the thread, drop offer / contract / screenshots, or type where things stand.
| Stage | What happens |
|---|---|
| Ask | AddConvAG reads the paste. If the brand is already named, it does not ask again. If the other side is vague (“they”, “a guy at the event”), it asks once for the brand or company name. |
| Working | Progress is creating the conversation room, never “and offer”. |
| Done | Unique link, Copy, optional mailto. Open the conversation (talent thread), Add another, Close. The row is on this agent, outbound, counterpart = brand, no offer badge. |
Send by text and vanity URLs (mcdonalds-4kt9) are out of scope.
The unique URL is /z/{talentSlug}/{roomId} — the same shape as a normal
z-link deep link. It is a capability URL: whoever claims first owns the
visitor seat.
Welcome copy:
Special cases on that URL:
| Who opens the link | What they get |
|---|---|
| Anonymous brand | Welcome + Sign up, then claim, then chat |
| Logged-in brand, seat still free | Welcome + Continue, then claim |
| Talent (the host) | “This is your conversation link” — they do not become the brand |
| Someone else after claim | “This invite was already claimed” — not a new guest room |
Once they are in chat, the page should look like a normal z-link (hero + chat), not a conversation picker with a plus. The host-facing agent already has the seeded brief, so the brand should not have to type “hey” for the agent to know this is the McDonald’s thread.
The z-link host is the negotiator. If it also ran this intake, it would be tempted to treat the pasted thread as a settled offer. AddConvAG’s only job is: brief + brand name, then stop. Code creates the room.
The same split exists elsewhere: Test agent invents an inbound without becoming the host persona. AddConvAG is the outbound twin — a real thread coming in from the talent, not a rehearsal.
Ops lists it with the others so the prompt is visible and downloadable. It still does not sit in the deal-room cast in The Agents. Those eleven roles mediate a live conversation. AddConvAG never enters that room.
Kind: deal, on the current talent (or the acted-as talent). Title
{Brand} × {Talent}.
zly_z_agent_guest cookie — that would lock
the brand out.invite (source add-conv), the summary, the brief as
visitor.externalThread, and visitor guidance: prior context, not a
settled offer. Do not mint from the seed alone.A bare /z/:slug (no roomId) must not resume this invite room. Hitting
the unique /z/:slug/:roomId must not call ensureDealRoomForGuest and
mint a second empty room.
Claim is first-writer-wins (claimedByAccountId). After claim, existing
VisitorRoomChat continues on that roomId. Visitor account memory is
still not seeded — see
Identity and Representation.
demo / simulate.returnTo is the invite URL, not /dashboard.| Surface | Who starts it | Room | Offer |
|---|---|---|---|
| Bring a conversation to Z | Talent, from an off-platform thread | Outbound deal, unique /z/:slug/:roomId | None until the brand makes one in chat |
Public z-link /z/:slug | Brand / stranger | Inbound deal, guest cookie | Normal z-link path |
| Sibling new offer | Booked change, or new campaign after 7 days of silence | Always-insert deal for the same pair | None copied; fresh negotiation. See Sibling rooms |
| Test agent | Talent rehearsal | Fresh demo per run | Must not mint a live offer |
| Piece | Where |
|---|---|
| Talent page | packages/offers/client/src/app/components/agent/conversations/AddConvAGPage.tsx |
| + button | AddConversationButton.tsx on talent (and act-as) conversation views |
| Welcome / brief card | packages/offers/client/src/app/components/zlink/ |
| AddConvAG prompt + turn | packages/z-agent/srv/src/add-conversation.ts, DEFAULT_ADD_CONV_PROMPT in agents/default-prompts.ts |
| Catalog / ops row | add-conversation in packages/z-agent/srv/src/agents/catalog.ts |
| Invite memory + claim | packages/z-agent/srv/src/add-conversation-invite.ts |
| Outbound room | createOutboundInviteDealRoom in packages/z-agent/srv/src/rooms.ts |
| HTTP | POST /api/z-agent/my/add-conversation/chat, GET / POST …/visitor/invite/:slug/:roomId |
Durable memory is in Memory. Host vs visitor seeding
is in Identity and Representation.
How a public /z/:slug normally opens is in
Rooms in the Product.