Developer docs · Browse & search
React hooks and components
@jwtson/react: start runs, follow them, chat, and answer questions and approvals in your own UI.
React hooks and components for a signed-in user's page, on top of @jwtson/sdk. Your server makes a client session and the page uses what it gives. The API key never reaches the browser.
import { connectClient } from '@jwtson/sdk';
import { JwtsonProvider, PendingRequests, useChat, useRun, useStart } from '@jwtson/react';
const client = connectClient(await fetch('/session', { method: 'POST' }).then(reply => reply.json()));
function Summarize() {
const { start, run, starting, error } = useStart('summarize');
const live = useRun(run);
return <>
<button disabled={starting} onClick={() => start({ document: 'd1' })}>Summarize</button>
{error && <p role="alert">{error.message}</p>}
<p>{live.text}</p>
<PendingRequests items={live.pending} />
</>;
}Put <JwtsonProvider client={client}> around your app. apps/client-example is a complete app with its server.
Hooks
| Hook | What it gives |
|---|---|
useStart(target, { group }) | start(input), run, starting, error, reset(). Pressing twice starts it once, and retrying after a failure reaches the same run if the first attempt got through |
useRun(run or id) | status, state, phase, text, events, pending, result, error, finished, canCancel, gap, plus cancel() and say(text). Unmounting stops watching, not the run |
useChat(target, { group, id }) | messages, send(text or { input }), current (useRun of the turn in progress), sending, error, id. Pass id to carry on an earlier chat |
useRuns({ group, limit }), useChats({ group, limit }) | The newest 50 unless you say otherwise: items (null while loading), error, refresh() |
Components
Unstyled, with real form controls and labels. Pass className and use your own CSS. What a run supplies is shown as text, never as HTML.
| Component | What it does |
|---|---|
PendingRequests | Everything in items, each in the right form below |
InputRequest | A question. A flat schema of text, number, yes/no and fixed-choice fields becomes a form. Anything else asks for JSON. The server checks the answer against the schema either way |
ApprovalRequest | What's proposed, with Approve, Reject, a comment and, where the workflow allows it, Request changes. If it changed since it was read, the decision is refused and this says so. Someone who can't decide sees no buttons |
RunProgress | Where the run really stands, in a live region that screen readers announce. It never estimates a percentage. labels replaces the wording. A failure is an alert, and a stop someone asked for isn't |
ResultFiles | A Save button for each file the run delivered, with its size. The secret stays in a header, so files are fetched rather than linked to |
A session only gets approvals its role can read, so someone without the reviewer role has nothing in pending for one. RunProgress shows them "Waiting for approval". A question shows its form only to someone who can answer it. A viewer or reviewer sees the question without one. useClientSession() gives the page its role, so you can leave out Start and Send for those roles too, as the example does. The server refuses them anyway.
When things go wrong
- The connection drops: following picks up by itself. Text so far is only a preview, so it starts over, and
gapsays some was missed. The finishedresultreplaces it. - The session ends: pass
getSecrettoconnectClient. The request is retried once with what your server gives, and nothing is started again. - The person is signed out or loses access:
erroris set, following stops,pendingempties, and the last known state stays on screen. The run keeps going, and your server can still reach it. - Leaving a page, or remounting: only watching stops.
Pages can save delivered files, and can't list or read the run's working folder.
Without React
run.watch() in @jwtson/sdk is what useRun is built on: subscribe, getSnapshot and stop, for any framework.
From the @jwtson/react README, as the code stands.