Partner SDK for AskTheo. Your backend authenticates itself once with
client_credentials, then asks AskTheo for a short-lived delegated session for a user
you have already authenticated. Your users never see a WorkOS or AskTheo login screen, and
there is no OAuth redirect anywhere in the flow.
Add to your project's .npmrc:
@harrisx:registry=https://sdk.justasktheo.com/npm/
npm install @harrisx/asktheo
Full guide: INTEGRATION.md.
import { AskTheo } from "@harrisx/asktheo";
const asktheo = new AskTheo({
partner: {
clientId: process.env.PARTNER_M2M_CLIENT_ID!,
clientSecret: process.env.PARTNER_M2M_CLIENT_SECRET!, // server-side only
},
});
1. Register a user, once. No invitation is sent and no password is set. Idempotent. The email must be on a domain your organization has verified with us.
await asktheo.registerUser({
subject: user.id, // your stable, immutable user id
email: user.email,
name: user.name,
workspaceId: user.workspaceId,
});
2. Delegate a session, per sign-in. Returns a token scoped to that user. A subject you
have not registered is rejected with user_not_registered.
const session = await asktheo.completeAuthentication({
subject: user.id,
email: user.email,
workspaceId: user.workspaceId,
authenticatedAt: user.authenticatedAt, // unix seconds, within the last 5 minutes
});
// session.accessToken, session.expiresIn (900s), session.tenant
Hand only session.accessToken to the browser. Keep clientSecret on your server.
const stream = await asktheo.ask({ question: "What are the top Q3 trends?" });
for await (const chunk of stream) {
if (chunk.text) process.stdout.write(chunk.text);
}
Or collect it all: const answer = await stream.result();
Pass reportSettings to switch the agent into report mode:
const stream = await asktheo.ask({
question: "Build the Q3 deck",
reportSettings: {
output_format: "powerpoint", // "powerpoint" | "charts_only" | "interactive"
verbosity: "short", // "short" | "medium" | "heavy"
style: "briefing",
color_palette: "corporate",
inline_preview: true,
},
});
Expose one authenticated route on your server that returns the delegated token, then drop in the component. Partner credentials stay on your server.
React — verified on React 18.3 and 19.3 (react is an optional peer, >=18):
import { AskTheoAsk } from "@harrisx/asktheo/react";
<AskTheoAsk /> {/* paths discovered; override with backend="…" */}
Headless instead — useAskTheo({ backend }) returns
{ ask, answer, chunks, isStreaming, sessionId, error, abort, reset }.
Any other frontend — a custom element, no build step:
<script type="module" src="/static/asktheo-element.js"></script>
<asktheo-ask backend="/internal/asktheo"></asktheo-ask>
Programmatic — AskTheoClient from @harrisx/asktheo/browser, with a tokenProvider
pointing at your route.
The /react, /browser and /element entries contain no partner functions at all, so a
clientSecret cannot reach a browser bundle by accident.
In Python, AskTheoComponent serves the other half: component.token(...) for your route and
component.embed_html(...) for the markup.
authenticateAs(...) is a server-side shortcut that delegates and adopts the token on
the same client, so it can call ask() immediately as that user.
await asktheo.deactivateUser({ subject: user.id, workspaceId: user.workspaceId });
Deactivates the membership and revokes sessions. Tokens already issued stay valid until they expire, which is why the lifetime is short.
The same lifecycle is available server-side in Python — see INTEGRATION.md.
Every failure returns { code, message }. Do not retry 400/401/403/409/422.
Retry 429 per Retry-After, and use bounded backoff for 502/503. The full table is in
INTEGRATION.md.
UNLICENSED — distributed to HarrisX partners under agreement.
Raw Markdown: readme.md