Skip to main content
The @polpo-ai/sdk works in React Native out of the box — it uses fetch and EventSource which are available in the React Native runtime.

Install

npm install @polpo-ai/sdk
For SSE support, install an EventSource polyfill:
npm install react-native-sse

Setup

// lib/polpo.ts
import { PolpoClient } from "@polpo-ai/sdk";

export const client = new PolpoClient({
  baseUrl: "https://api.polpo.sh",
  apiKey: "pk_live_...",
});

Chat screen

import { useState, useCallback } from "react";
import { View, TextInput, FlatList, Text, TouchableOpacity } from "react-native";
import { client } from "../lib/polpo";

interface Message {
  role: "user" | "assistant";
  content: string;
}

export function ChatScreen() {
  const [messages, setMessages] = useState<Message[]>([]);
  const [input, setInput] = useState("");
  const [streaming, setStreaming] = useState(false);

  const send = useCallback(async () => {
    if (!input.trim() || streaming) return;
    const userMsg: Message = { role: "user", content: input };
    const updated = [...messages, userMsg];
    setMessages(updated);
    setInput("");
    setStreaming(true);

    try {
      const stream = client.chatCompletionsStream({
        agent: "assistant",
        messages: updated,
      });

      let content = "";
      setMessages(prev => [...prev, { role: "assistant", content: "" }]);

      for await (const chunk of stream) {
        const delta = chunk.choices[0]?.delta?.content ?? "";
        content += delta;
        setMessages(prev => [
          ...prev.slice(0, -1),
          { role: "assistant", content },
        ]);
      }
    } catch (err) {
      setMessages(prev => [
        ...prev,
        { role: "assistant", content: "Error: " + (err as Error).message },
      ]);
    } finally {
      setStreaming(false);
    }
  }, [messages, input, streaming]);

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <FlatList
        data={messages}
        keyExtractor={(_, i) => String(i)}
        renderItem={({ item }) => (
          <View style={{ marginBottom: 12 }}>
            <Text style={{ fontWeight: "bold" }}>
              {item.role === "user" ? "You" : "Agent"}
            </Text>
            <Text>{item.content}</Text>
          </View>
        )}
      />
      <View style={{ flexDirection: "row", gap: 8 }}>
        <TextInput
          value={input}
          onChangeText={setInput}
          placeholder="Message..."
          style={{ flex: 1, borderWidth: 1, borderColor: "#ccc", padding: 8, borderRadius: 8 }}
          onSubmitEditing={send}
        />
        <TouchableOpacity onPress={send} disabled={streaming}>
          <Text>Send</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

Agent list

import { useEffect, useState } from "react";
import { View, Text, FlatList, Image } from "react-native";
import { client } from "../lib/polpo";

export function AgentsScreen() {
  const [agents, setAgents] = useState([]);

  useEffect(() => {
    client.getAgents().then(setAgents);
  }, []);

  return (
    <FlatList
      data={agents}
      keyExtractor={(a) => a.name}
      renderItem={({ item }) => (
        <View style={{ flexDirection: "row", padding: 16, gap: 12 }}>
          {item.identity?.avatar && (
            <Image
              source={{ uri: item.identity.avatar }}
              style={{ width: 40, height: 40, borderRadius: 20 }}
            />
          )}
          <View>
            <Text style={{ fontWeight: "bold" }}>
              {item.identity?.displayName ?? item.name}
            </Text>
            <Text style={{ color: "#666" }}>{item.role}</Text>
          </View>
        </View>
      )}
    />
  );
}

SSE events

For real-time updates, use react-native-sse:
import EventSource from "react-native-sse";

const url = client.getEventsUrl(["task:", "agent:"]);
const es = new EventSource(url, {
  headers: { "x-api-key": "pk_live_..." },
});

es.addEventListener("task:transition", (event) => {
  const data = JSON.parse(event.data);
  console.log("Task moved to:", data.to);
});

// Cleanup
es.close();

Notes

  • The @polpo-ai/react hooks package uses useSyncExternalStore which works on React Native 0.69+
  • For Expo, all APIs work without extra native modules
  • File uploads (agent avatars, storage) use standard fetch with FormData
  • Chat streaming uses the Fetch API’s ReadableStream — supported in React Native 0.71+ (Hermes)
For older React Native versions without ReadableStream support, use the non-streaming client.chatCompletions() method instead.