npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thg-agentic/chatbot-sdk-react-native

v0.2.5

Published

React Native SDK for the THG AI Shopping Assistant — exports a single <Chatbot /> component that host apps can mount however they like.

Readme

@thg-agentic/chatbot-sdk-react-native

React Native SDK for the THG AI Shopping Assistant. Exports a single <Chatbot /> component that you mount wherever makes sense in your app — full screen, modal, drawer, bottom sheet.

Install

npm install @thg-agentic/chatbot-sdk-react-native

Required peer dependencies:

npm install react@>=18 react-native@>=0.72 react-native-svg

SSE streaming on React Native: the SDK uses fetch + ReadableStream for AG-UI streaming. Bare RN 0.72+ supports this on iOS, but Android can need a polyfill. Install react-native-polyfill-globals and add import 'react-native-polyfill-globals/auto'; to your app entry if you see "response.body is undefined" errors.

Optional peers (per feature)

| Feature | Peer dependency | What you get | |---|---|---| | Persistent session/conversation across launches | @react-native-async-storage/async-storage (async) or react-native-mmkv (sync) | Conversation history survives app restart | | Voice-to-text | @react-native-voice/voice | Mic button + live transcript | | Image upload | expo-image-picker (preferred) or react-native-image-picker | Attach button + base64 upload | | iOS Health activity connector | react-native-health | Lets the agent request a consent-gated Apple Health activity summary for fitness-informed Myprotein guidance |

If a peer isn't installed, the corresponding feature is silently hidden — no errors, no setup gymnastics.

iOS Health activity

The Health connector is opt-in at three layers:

  1. The backend /v1/config capability must return healthActivity: true for the channel.
  2. The native app must install and configure react-native-health with the required iOS HealthKit entitlement and NSHealthShareUsageDescription.
  3. The native app must pass a health.readActivity callback. The SDK declares get_health_activity only when both the backend capability and callback are present.
import { Chatbot } from '@thg-agentic/chatbot-sdk-react-native';
import {
  createAppleHealthKitActivityProvider,
  requestAppleHealthKitActivityAuthorization,
} from '@thg-agentic/chatbot-sdk-react-native/health/ios';

const health = createAppleHealthKitActivityProvider({
  defaultLookbackDays: 14,
  includeManuallyAdded: false,
});

// Recommended from a user action, e.g. a "Connect Apple Health" button.
await requestAppleHealthKitActivityAuthorization();

<Chatbot
  config={{
    channel: 'myprotein',
    locale: 'en-GB',
    apiUrl: 'https://api.thg.dev/agentic-commerce/shopping-assistant/ag-ui',
    apiKey: '<per-storefront-key>',
    health,
  }}
/>;

The adapter asks HealthKit for read access to step count, active energy, walking/running distance, workouts, and sleep analysis. It returns a bounded aggregate snapshot rather than raw samples, and partial permission/read failures are reported in the snapshot so the agent can explain what is missing. If the host does not preflight authorization, the adapter still calls HealthKit authorization when the agent first invokes get_health_activity; preflighting just makes the consent sheet explicit and easier to test.

iOS does not provide a supported deep link to an app's Health data-type permissions. If a user needs to review or change access after the first prompt, guide them to Health app > profile picture > Apps > your app, or Settings > Health > Data Access & Devices > your app.

Use

import { useEffect, useState } from 'react';
import { Chatbot } from '@thg-agentic/chatbot-sdk-react-native';
import type { StorageAdapter } from '@thg-agentic/chatbot-sdk-react-native';
import { createAsyncStorageAdapter } from '@thg-agentic/chatbot-sdk-react-native/storage/async-storage';

export function ChatScreen({ navigation }) {
  const [storage, setStorage] = useState<StorageAdapter | null>(null);

  useEffect(() => {
    const adapter = createAsyncStorageAdapter();
    let mounted = true;

    adapter.ready().then(() => {
      if (mounted) setStorage(adapter);
    });

    return () => { mounted = false; };
  }, []);

  if (!storage) return null;

  return (
    <Chatbot
      config={{
        channel: 'myprotein',
        locale: 'en-GB',
        apiUrl: 'https://api.thg.dev/agentic-commerce/shopping-assistant/ag-ui',
        apiKey: '<per-storefront-key>',
        theme: {
          primaryColor: '#003942',
          accentColor: '#003942',
        },
        content: {
          headerTitle: 'Fuel Coach',
          welcomeMessages: ['Hi! Ask me about anything from our range.'],
        },
        features: {
          showSuggestions: true,
          showFeedback: true,
          imageUpload: true,
          // In production this is overlaid from /v1/config; shown here only
          // for local mocks that bypass the config bootstrap.
          healthActivity: true,
        },
        health: createAppleHealthKitActivityProvider(),
      }}
      storage={storage}
      onSettingsPress={() => navigation.navigate('Personalisation')}
      onProductPress={(product) => navigation.navigate('PDP', { sku: product.sku })}
      onError={(code, message) => console.warn('[Chatbot]', code, message)}
    />
  );
}

Props

| Prop | Type | Notes | |---|---|---| | config | ChatbotConfig | Required. Same shape as the web SDK. | | storage | StorageAdapter | Optional. Defaults to in-memory (resets on reload). | | onProductPress | (p: CarouselProduct) => void | Override default product navigation. Without an override, the SDK opens http(s) product URLs with Linking.openURL; relative catalog paths are resolved against config.siteUrl. | | onError | (code, message) => void | Fires for every chat-stream error. | | onSettingsPress | () => void | Optional. Renders a header control that lets the host open its own memory/connectors/personalisation screen. | | onMemoryConsentChange | (detail: MemoryConsentChangedDetail) => void | Required (with onSettingsPress) to show the in-chat memory opt-in card — the SDK won't offer an opt-in it can't persist or that the user can't reverse. Fires on accept/decline so the host persists the decision; the SDK reflects it for the session (badge + per-request memory_settings). | | style | ViewStyle | Applied to the outer container. |

The ChatbotConfig shape covers theme colors, content/i18n strings, feature flags, analytics callbacks, and session/customer identifiers. See @thg/chatbot-sdk-core's types.ts for the full interface.

Theming (multi-brand)

The UI is fully theme-driven — there are no brand colours baked into the components. Every brand (Myprotein, Lookfantastic, Cult Beauty, …) ships the same SDK and restyles it entirely through config.theme:

| Token | Drives | |---|---| | primaryColor | header title + icons, filled CTAs ("Turn on memory", send button when active), suggestion-chip outline, settings toggles | | primaryTextColor | text/icon colour on primaryColor fills | | accentColor | the sparkle mark, the active input-pill border, the voice waveform, review stars | | textColor | body + answer text | | textMutedColor | disclaimer, placeholder, review counts, struck-through RRP | | surfaceColor | raised neutral fills — user bubble, input pill, header icon circles, "memory on" badge (defaults to light grey; set it for dark brands) | | backgroundColor | chat background | | borderColor | dividers, card outlines | | errorColor | discount text + (with priceFormat: 'default') the "(N% off)" tag | | radius | base corner radius | | sparklesSvg | optional override for the header/suggestions sparkle glyph |

Anything left unset falls back to a neutral default, so a minimal { primaryColor, accentColor } already produces a coherent look. The example app ships three brand presets (config.ts) selectable with EXPO_PUBLIC_CHATBOT_BRAND=lookfantastic to demonstrate that the identical screens restyle per brand.

Internationalisation

i18n works out of the box. All user-facing copy is resolved through @thg/chatbot-sdk-core's label() against the locale pack chosen by config.locale (31 built-in languages, including the cross-session memory copy). Pass locale: 'fr-FR' (etc.) and the header, memory consent card, suggestions, feedback, errors and thinking states all render translated — no per-brand string tables required. Host overrides go in config.content (merged on top of the locale pack), so a brand can sharpen a few strings (e.g. the memory examples) without losing translations for everything else.

Storage adapters

The SDK uses a small, synchronous StorageAdapter contract:

interface StorageAdapter {
  getItem(key: string): string | null;
  setItem(key: string, value: string): void;
  removeItem(key: string): void;
}

Three built-in factories:

import { InMemoryStorageAdapter } from '@thg-agentic/chatbot-sdk-react-native';
import { createAsyncStorageAdapter } from '@thg-agentic/chatbot-sdk-react-native/storage/async-storage';
import { createMMKVStorageAdapter } from '@thg-agentic/chatbot-sdk-react-native/storage/mmkv';
  • InMemoryStorageAdapter — default. Conversation resets on reload.
  • createAsyncStorageAdapter() — async backend, sync façade via an in-memory cache pre-warmed at construction. Call await adapter.ready() before mounting <Chatbot /> so the first render reads the persisted session and conversation.
  • createMMKVStorageAdapter() — fully synchronous, recommended if you're already using MMKV in your app.

You can also implement StorageAdapter against your own store (SecureStore, Keychain, etc.).

What's not in this package

The web SDK has FAB triggers, popup/sidebar layouts, drag/resize, and a launcher hub for multiple assistants. None of that is here — the host app owns presentation. If you need a multi-assistant entry point, build your own screen that decides which assistantId to pass.

Example app

A working Expo example lives at ./example. After pnpm install at the repo root:

cd packages/chatbot-sdk/react-native/example
pnpm ios               # or: pnpm android, pnpm web, pnpm start

Metro is set up for the monorepo, so edits to this package (and to @thg/chatbot-sdk-core) hot-reload without any extra build step. See example/README.md for backend wiring and notes on which features run in Expo Go vs. need a dev build.

Local development

This package lives in the THG chatbot-adk monorepo. From the repo root:

pnpm install
pnpm --filter @thg-agentic/chatbot-sdk-react-native typecheck
pnpm --filter @thg-agentic/chatbot-sdk-react-native test
pnpm --filter @thg-agentic/chatbot-sdk-react-native lint

The package's main entry resolves to ./src/index.ts (via the example's Metro config) so linked monorepo consumers (e.g. the Expo example app under ./example) see live TypeScript edits without a build step.

The web SDK's mock API server at packages/web/scripts/dev-server.js exposes POST /v1/chat for local prototyping, but the AG-UI streaming endpoint isn't mocked there — use a real dev backend or write a lightweight SSE mock for now.