@mohaa24/agent-iframe-sdk
v1.4.0
Published
SDK for client apps embedding the Seer agent in an iframe: postMessage protocol, app context, and cross-app form routing/handoff.
Maintainers
Readme
Agent Iframe SDK (Seer SDK)
SDK for client apps that embed the agent (Seer) in an iframe. Provides a SeerSDK class that handles postMessage listening, app context passing, and cross-app form handoff via common localStorage (pending actions with 30s expiry).
Integration guide
For full architecture, message protocol, form routing/prefill flow, and onboarding steps for new client apps, see:
./INTEGRATION_GUIDE.md
Build
From repo root:
yarn build:sdkOr from this folder:
yarn buildExport for client app
From repo root, pack the SDK so the client app can install from the tarball:
yarn build:sdk && cd sdk && yarn packIn your client app, install from the SDK repo tarball (not a copy stored in the client repo, or you may get a 404 for agent-messaging-types):
yarn add '/path/to/mp-partners-agent-web-1/sdk/package.tgz'Or copy the new package.tgz from the SDK repo into your client repo, then add it. If you see a 404 for @mp-partners-agent-web/agent-messaging-types, the tarball you're adding is an old one; use the freshly packed tarball from the SDK repo.
Recommended: SeerSDK class
Use the SeerSDK class so the SDK owns the listener, app context, and cross-app handoff. You only pass app name, onFormUpdate, and optionally the iframe ref. App config is shipped inside the SDK. When the SDK finds a pending action on init, it sends window.parent.postMessage({ type: 'toggleAIChat', show: true }, '*') so the parent/host can show the Seer iframe.
'use client';
import { useEffect, useRef, useState } from 'react';
import { SeerSDK } from '@mp-partners-agent-web/agent-iframe-sdk';
export default function Layout({ children }) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const sdkRef = useRef<SeerSDK | null>(null);
const [showAIChat, setShowAIChat] = useState(false);
useEffect(() => {
const sdk = new SeerSDK({
appName: 'mp-partner-identity-web',
onFormUpdate: (formName, formData) => {
// Handle form in this app: e.g. router.push(...), setFormValues(formData)
},
targetOrigin: '*',
});
sdkRef.current = sdk;
sdk.init();
return () => {
sdk.destroy();
sdkRef.current = null;
};
}, []);
useEffect(() => {
if (iframeRef.current) sdkRef.current?.setIframe(iframeRef.current);
}, [showAIChat]);
// Listen for toggleAIChat from SDK (pending action) or from agent iframe
useEffect(() => {
const handler = (event: MessageEvent) => {
if (event.data?.type === 'toggleAIChat' && typeof event.data?.show === 'boolean') {
setShowAIChat(event.data.show);
}
};
window.addEventListener('message', handler);
return () => window.removeEventListener('message', handler);
}, []);
return (
<>
{showAIChat && (
<iframe ref={iframeRef} src="https://your-agent-url" title="Agent" />
)}
{children}
</>
);
}toggleAIChat
The SDK sends { type: 'toggleAIChat', show: true } to window.parent when it finds a pending action on init (so the parent can open the Seer iframe). The agent iframe can also send the same message to show/hide the chat. Your parent/client app should listen for this and toggle iframe visibility. Example:
useEffect(() => {
const handler = (event: MessageEvent) => {
if (event.data?.type === 'toggleAIChat' && typeof event.data?.show === 'boolean') {
setShowAIChat(event.data.show);
}
};
window.addEventListener('message', handler);
return () => window.removeEventListener('message', handler);
}, []);Pending actions and 30s expiry
- When a form belongs to another app, the SDK writes a pending action to common localStorage and redirects to that app. That app’s SDK on init reads the pending action; if it’s not older than 30 seconds, it sends
window.parent.postMessage({ type: 'toggleAIChat', show: true }, '*')(so the parent can show the iframe), then runs the handler (e.g.onFormUpdate) and clears storage. Entries older than 30s are ignored and cleared. - Pending items are stored as generic actions (e.g.
form_updatetoday; more action types can be added later).
Low-level API (optional)
If you prefer to wire things yourself:
- createAgentIframeListener(options) — returns an unsubscribe function. Options:
targetOrigin,onFormUpdate,onRouting. - sendAppContext(iframe, appName, targetOrigin?) — posts
app_contextto the iframe.
You can also import SEER_PENDING_ACTION_STORAGE_KEY and TPendingAction / TPendingActionPayloadFormUpdate if you need to read or extend pending actions.
Message types
- Agent → Client:
{ action: 'form_update', payload: { formName, formData } }or{ action: 'routing', payload: { app, page, view? } } - Client → Agent:
{ type: 'app_context', payload: { appName } } - Agent → Client (toggle):
{ type: 'toggleAIChat', show: boolean }— implement listener in your app as above.
Types are exported from the SDK (TAgentToClientMessage, TClientToAgentMessage, TFormName, TSeerSDKConfig, etc.).
