HarrisX

AskTheo SDK — Quick Reference

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.

Install

Add to your project's .npmrc:

@harrisx:registry=https://sdk.justasktheo.com/npm/
npm install @harrisx/asktheo

Full guide: INTEGRATION.md.

Two calls

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.

Asking questions

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();

Report generation

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,
  },
});

In the browser

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>

ProgrammaticAskTheoClient 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.

Removing access

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.

Python

The same lifecycle is available server-side in Python — see INTEGRATION.md.

Errors

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.

License

UNLICENSED — distributed to HarrisX partners under agreement.

Raw Markdown: readme.md