@personaai/react 0.17.0 → 0.18.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  React SDK for [Persona](https://persona.hasanraiyan.me) — hooks and a context provider for building chat UIs against any Persona backend.
4
4
 
5
- > **v0.9.0.** Requires React 18+. Client-side only — never holds a credential.
5
+ > **v0.17.0.** Requires React 18+. Client-side only — never holds a credential.
6
6
 
7
7
  ## Install
8
8
 
@@ -48,19 +48,61 @@ function Chat() {
48
48
 
49
49
  | Hook | Purpose |
50
50
  | -------------------- | ----------------------------------------------------------------------------------------------- |
51
- | `useChat` | Streaming chat — messages, send, stop, reload, interrupts, workspace files, ephemeral new chat |
51
+ | `useChat` | Streaming chat — messages, send, stop, reload, interrupts, live workspace/todo state, sandbox commands, ephemeral new chat |
52
52
  | `useArchitectChat` | Streaming chat with the Agent Architect co-pilot — same mechanics as `useChat`, no `agentId` |
53
53
  | `useWorkflowStream` | Live streaming workflow execution — real-time node state tracking, cancellation, and resume |
54
54
  | `useWorkflows` | Workflow discovery & creation — list, paginate, filter, and create workflows |
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
- | `useMemory` | Persistent memory — read, write, delete |
61
- | `useAgents` | Agent discovery — list available agents |
61
+ | `useMemory` | Persistent memory CRUD — `scope: "user" \| "agent" \| "workspace"` (an Agent's own `/workspace/` files) |
62
+ | `useWorkspaceFiles` | Thin wrapper over `useMemory` (`scope: "workspace"`) scoped to one Agent — list/get/write/delete |
63
+ | `useAgents` | Agent discovery — list available agents (`visibility: "public"` or self-owned only) |
64
+ | `useSkills` | Skill CRUD — list, create, update, delete, usage |
65
+ | `useKnowledgeBases` | Knowledge base CRUD + document upload/search |
66
+ | `useRcpSources` | RCP source CRUD + test connection |
67
+ | `useMcpAdmin` | Self-serve MCP connector CRUD (`scope: "mine"` only) |
68
+ | `useMcp` | MCP discovery + tool listing |
69
+ | `useMcpConnections` | End-user MCP OAuth connect/disconnect flow |
62
70
  | `useConnection` | Health check — backend connectivity status |
63
71
 
72
+ ## Memory & an Agent's `/workspace/` files
73
+
74
+ ```tsx
75
+ const { memory, getFile, writeFile, deleteFile } = useMemory();
76
+
77
+ // memory.userFiles (shared across every Agent), memory.agentMemories, and
78
+ // memory.agentWorkspaces are each PersonaMemoryAgentGroup[] — grouped one entry per Agent.
79
+ await writeFile({ path: "/preferences.md", content: "Prefers concise answers.", scope: "user" });
80
+
81
+ // An Agent's own /workspace/ files — the SAME persistent store its `write_file`/`read_file` tool
82
+ // calls use (NOT a Thread's live/checkpointed state, a different, much narrower thing). Shared
83
+ // across every Thread this Subject has with that Agent, not private to one conversation.
84
+ const report = await getFile({ path: "/outputs/report.md", scope: "workspace", agentId });
85
+ ```
86
+
87
+ `useWorkspaceFiles(agentId)` is a thinner wrapper over the same `scope: "workspace"` calls, scoped
88
+ to one Agent up front — handy for a dedicated file-explorer UI that isn't inside an active chat:
89
+
90
+ ```tsx
91
+ const { files, isLoading, writeFile, deleteFile } = useWorkspaceFiles(agentId);
92
+ ```
93
+
94
+ `useChat()`'s own `files`/`todos` are a different, read-only, per-Thread live snapshot (from
95
+ `STATE_SNAPSHOT` events during a run) — use `useWorkspaceFiles`/`useMemory` for CRUD independent of
96
+ an active chat session.
97
+
98
+ ## Sandbox terminal
99
+
100
+ If an Agent has `sandboxEnabled: true` (check the active Thread's populated `agentId` — see
101
+ `@personaai/sdk`'s README), its `execute` tool calls are real shell commands in an isolated VM, not
102
+ simulated. `useChat()`'s `sandboxCommands: PersonaSandboxCommand[]` is a pure derived view over the
103
+ same tool-call stream already backing `messages` — `{ toolCallId, command, output, exitCode,
104
+ status }` — enough to build a read-only terminal-style replay with no separate fetch or polling.
105
+
64
106
  ## Voice
65
107
 
66
108
  Real-time voice calls with an Agent, powered by Gemini Live. Requires your backend to be running
@@ -130,6 +172,60 @@ as a text response). Injected messages get a `voice-`-prefixed id. You still cal
130
172
  / `voice.stop()` yourself — `useChat` only owns the transcript-to-feed sync, not the call
131
173
  lifecycle.
132
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
+
133
229
  ## Ephemeral new chat (0.8.0+)
134
230
 
135
231
  Create a new chat instantly without minting an empty thread. The real `threadId` is created lazily on the first `sendMessage`.