La documentazione per sviluppatori è in inglese.
Documentazione
WebKnox in the AI SDK
@webknox/ai-sdk adds one tool to the AI SDK, askWebknox. When a question has a WebKnox answer, your app shows its card, and the model adds only what the card doesn't say.
Add the tool
The tool works with AI SDK 6 and 7, on any model that can call tools.
npm install @webknox/ai-sdk
Set WEBKNOX_API_KEY on your server, with a key from the console, and add the tool to your route:
import {convertToModelMessages, isStepCount, streamText} from 'ai';
import {askWebknox} from '@webknox/ai-sdk';
const tools = {askWebknox: askWebknox()};
export async function POST(request) {
const {messages} = await request.json();
const result = streamText({
model: 'openai/gpt-5-mini',
system: 'Use askWebknox for anything it covers, even in a follow-up.',
messages: await convertToModelMessages(messages, {tools}),
tools,
stopWhen: isStepCount(3),
});
return result.toUIMessageStreamResponse();
}
Models differ in how readily they call a tool, and some write a recipe from memory instead. The system line above tells yours to prefer WebKnox.
Show the card
The tool's result is the whole answer. In a chat built with useChat it arrives as a message part named after the tool:
message.parts.map((part) => {
if (part.type === 'text') return <p>{part.text}</p>;
if (part.type === 'tool-askWebknox' && part.state === 'output-available') {
return <AnswerCard answer={part.output} onAsk={(text) => sendMessage({text})} />;
}
});
<webknox-answer> from @webknox/elements draws every card type. It registers itself in the browser, so load it in an effect:
function AnswerCard({answer, onAsk}) {
const ref = useRef(null);
useEffect(() => {
import('@webknox/elements');
const element = ref.current;
element.answer = answer;
const ask = (event) => onAsk(event.detail.text);
const refine = async (event) => {
event.preventDefault();
const {refine, done} = event.detail;
const shown = element.answer;
const response = await fetch('/api/refine', {
method: 'POST',
body: JSON.stringify({question: shown.card.data.query ?? shown.text, locale: shown.locale, refine}),
});
if (response.ok) element.answer = await response.json();
else done();
};
element.addEventListener('webknox-follow-up', ask);
element.addEventListener('webknox-refine', refine);
return () => {
element.removeEventListener('webknox-follow-up', ask);
element.removeEventListener('webknox-refine', refine);
};
}, [answer, onAsk]);
return <webknox-answer ref={ref} />;
}
A suggested question sends webknox-follow-up with a sentence, so onAsk passes it to sendMessage as a new turn.
A change to a search card's filters, sort or results fires webknox-refine. Don't send that through the model, which may answer in text and leave the card as it was. Answer it from your server with refineAnswer, and the card updates in place:
import {refineAnswer} from '@webknox/ai-sdk';
export async function POST(request) {
const {question, locale, refine} = await request.json();
return Response.json(await refineAnswer({question, locale, refine}));
}
Add your own auth and rate limits to that route before it goes public, since it spends your key. The Next.js chat is the complete app.
What the model reads
The UI gets the whole answer, and the model gets only its text and sources, with a note that the user already sees the card. A large card stays out of its context that way, and it doesn't read the card back to the user.
Pass the same tools object to convertToModelMessages, as above, so earlier turns are sent the same short way.
Options
The model passes one self-contained question. Everything else is set once, on the tool:
askWebknox({
locale: 'de',
context: {timezone: 'Europe/Berlin', units: 'metric'},
accept: ['weather.forecast', 'nutrition.facts'],
});
| Option | Meaning |
|---|---|
locale | en (default), de, fr, es, pt or it |
context | Time zone, current time, location and units, for “today” and “here” |
accept | The card types your app can show; omit it to accept all |
render | Hosted embeds and images, on Pro and Scale |
apiKey | Defaults to WEBKNOX_API_KEY |
baseUrl, fetch | For proxies and tests |
No answer and errors
A question WebKnox can't answer returns matched: false. The model is told so and answers it itself, and the call isn't billed.
A refused request throws a WebKnoxError with status, code and retryAfterS, from the API's errors. The AI SDK passes it to the model as a failed tool call.