@tenzro/ai-react
v0.4.15
Published
React hooks for Tenzro AI SDK — useChat, useCompletion, useObject. Streams Tenzro inference (text, reasoning, tool calls, attestation, ZK proof, payment receipts) into your UI.
Maintainers
Readme
@tenzro/ai-react
React hooks for Tenzro AI SDK —
useChat,useCompletion,useObject.
Streams Tenzro inference (text, reasoning, tool calls, attestation, ZK proof, payment receipts) into your UI.
npm install @tenzro/ai @tenzro/ai-react reactHooks
| Hook | Use case | Key state |
|---|---|---|
| useChat | Multi-turn chat transcript | messages: UIMessage[], status, submit, stop |
| useCompletion | Single-shot prompt → response | prompt, completion, reasoning, submit |
| useObject<T> | Schema-validated streaming JSON | partial: Partial<T>, object: T, submit |
Each hook is a thin useSyncExternalStore shim over a pure-TypeScript runner (ChatRunner, CompletionRunner, ObjectRunner<T>). The runners are exported too — use them directly to integrate with non-React UIs (Solid, Svelte, vanilla).
useChat
import { useChat } from '@tenzro/ai-react';
import { tenzro } from '@tenzro/ai';
function Chat() {
const { messages, status, submit, stop } = useChat({
model: tenzro('llama-3.3-70b'),
});
return (
<>
<ul>
{messages.map((m) => (
<li key={m.id}>
<b>{m.role}</b>:{' '}
{m.parts.map((p, i) => (p.type === 'text' ? <span key={i}>{p.text}</span> : null))}
</li>
))}
</ul>
<form
onSubmit={(e) => {
e.preventDefault();
const input = (e.target as HTMLFormElement).elements.namedItem('msg') as HTMLInputElement;
submit(input.value);
input.value = '';
}}
>
<input name="msg" disabled={status === 'streaming'} />
{status === 'streaming' ? <button onClick={stop}>Stop</button> : <button>Send</button>}
</form>
</>
);
}messages is readonly UIMessage[]. Each UIMessage.parts is a discriminated union covering text, reasoning, tool-call, source, tenzro-attestation, tenzro-zk-proof, tenzro-payment-receipt. Render whichever part types your UI cares about.
status is 'idle' | 'streaming' | 'error'. Use it to disable the input during a stream.
useCompletion
import { useCompletion } from '@tenzro/ai-react';
import { tenzro } from '@tenzro/ai';
function Suggest() {
const { completion, reasoning, status, submit } = useCompletion({
model: tenzro('llama-3.3-70b'),
});
return (
<>
<button onClick={() => submit('Suggest a name for a coffee shop.')}>Suggest</button>
{reasoning && <pre className="reasoning">{reasoning}</pre>}
<p>{completion}</p>
</>
);
}reasoning accumulates separately from completion — render it as a collapsible "thinking" panel for models that emit chain-of-thought (e.g. qwen3-thinking).
useObject
import { useObject } from '@tenzro/ai-react';
import { tenzro } from '@tenzro/ai';
import { z } from 'zod';
const userSchema = z.object({
name: z.string(),
age: z.number(),
bio: z.string(),
});
function NewUser() {
const { partial, object, status, submit } = useObject({
model: tenzro('llama-3.3-70b'),
schema: userSchema,
});
return (
<>
<button onClick={() => submit('Make up a fake user profile.')}>Generate</button>
{/* `partial` updates progressively as the JSON streams in. */}
{partial?.name && <h2>{partial.name}</h2>}
{partial?.age && <p>Age {partial.age}</p>}
{partial?.bio && <p>{partial.bio}</p>}
{status === 'idle' && object && <pre>{JSON.stringify(object, null, 2)}</pre>}
</>
);
}partial: Partial<T> is what the runner has parsed so far. object: T is the final schema-validated value (only set after the stream closes successfully). If validation fails, the runner transitions to 'error' and the call's promise rejects.
Receipts and verification
Inference receipts ride alongside the snapshot. After a successful run:
const { messages, receipts } = useChat({ model: tenzro('llama-3.3-70b') });
if (receipts?.attestation) {
// Render a verification badge.
}
if (receipts?.payment) {
// Show settled amount and protocol.
}Verification badges in the chat transcript come through as parts on the assistant message — tenzro-attestation, tenzro-zk-proof, tenzro-payment-receipt — so you can render per-message badges directly.
Pure runners (advanced)
The runners are pure TypeScript with no React dependency. Use them for non-React frameworks or for tests:
import { ChatRunner } from '@tenzro/ai-react';
import { tenzro } from '@tenzro/ai';
const runner = new ChatRunner({ model: tenzro('llama-3.3-70b') });
const unsubscribe = runner.subscribe(() => {
console.log(runner.getSnapshot().messages);
});
await runner.submit('Hello.');
unsubscribe();Status
Pre-alpha. APIs may change without notice until 1.0.
License
Apache-2.0
