@personaai/react 0.17.1 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,6 +55,7 @@ function Chat() {
55
55
  | `useWorkflow` | Single workflow authoring — drafts, publishing, versions, and Mermaid diagrams |
56
56
  | `useWorkflowRuns` | Workflow run history — list historical runs, get run details, and cancel in-flight runs |
57
57
  | `useVoice` | Real-time voice calls (Gemini Live) — start/stop/mute, live transcript, tool calls |
58
+ | `useMessages` | Outbound SMS/WhatsApp — plain send or Agent-composed reply (`capabilities.messages`) |
58
59
  | `useThreads` | Thread CRUD — list, create, delete, rename, reset, archive |
59
60
  | `useFiles` | Upload management — list, upload, delete |
60
61
  | `useMemory` | Persistent memory CRUD — `scope: "user" \| "agent" \| "workspace"` (an Agent's own `/workspace/` files) |
@@ -171,6 +172,60 @@ as a text response). Injected messages get a `voice-`-prefixed id. You still cal
171
172
  / `voice.stop()` yourself — `useChat` only owns the transcript-to-feed sync, not the call
172
173
  lifecycle.
173
174
 
175
+ ## SMS and WhatsApp
176
+
177
+ `useMessages()` sends outbound text messages through your own backend's `POST /messages` /
178
+ `POST /messages/agent` routes (requires `@personaai/runtime@^0.16.0` or an adapter built on it).
179
+ Both routes are opt-in there — mount a runtime with `capabilities: { messages: true }`, or they
180
+ 404. That's deliberate: `to` is any E.164 number and every send spends the Project's Twilio
181
+ balance, so it isn't end-user-scoped the way `chat`/`voice` are. Anything your `resolveUser`
182
+ accepts on that mount can text arbitrary numbers through it, so enable it only where that's
183
+ acceptable.
184
+
185
+ ```tsx
186
+ import { useMessages } from "@personaai/react";
187
+
188
+ function FollowUp({ agentId }: { agentId: string }) {
189
+ const { send, sendFromAgent, isSending, error, lastDelivery } = useMessages();
190
+
191
+ return (
192
+ <div>
193
+ {/* Plain send — no Agent involved. */}
194
+ <button
195
+ onClick={() => send({ to: "+919876543210", body: "Your order shipped!" })}
196
+ disabled={isSending}
197
+ >
198
+ Text customer
199
+ </button>
200
+
201
+ {/* The Agent runs on the shared conversation and its reply is delivered. */}
202
+ <button
203
+ onClick={() =>
204
+ sendFromAgent({
205
+ agentId,
206
+ to: "+919876543210",
207
+ prompt: "Remind them their appointment is tomorrow at 10.",
208
+ })
209
+ }
210
+ disabled={isSending}
211
+ >
212
+ Have the agent follow up
213
+ </button>
214
+
215
+ {lastDelivery && <p>Sent in {lastDelivery.parts} part(s)</p>}
216
+ {error && <p role="alert">{error.message}</p>}
217
+ </div>
218
+ );
219
+ }
220
+ ```
221
+
222
+ The channel is inferred from a `whatsapp:` prefix on `to` (or pass `channel: "whatsapp"`). A body
223
+ is required unless you pass an approved WhatsApp template (`contentSid` + `contentVariables`) —
224
+ business-initiated WhatsApp messages outside the 24-hour session window need one. Conversations
225
+ are keyed by phone number, so SMS, WhatsApp, and voice with the same Agent share one thread;
226
+ `sendFromAgent()` continues it rather than starting fresh. Agents with guarded (`interruptOn`)
227
+ tools are rejected with a 422, same as voice — there's no confirmation flow on a text channel.
228
+
174
229
  ## Ephemeral new chat (0.8.0+)
175
230
 
176
231
  Create a new chat instantly without minting an empty thread. The real `threadId` is created lazily on the first `sendMessage`.