configure
v1.1.6
Published
Identity layer SDK for AI agents
Downloads
2,087
Maintainers
Readme
Configure TypeScript SDK
Configure is user-controlled memory for AI agents.
Configure is live for select teams. The SDK is public. Production credentials are issued after Launch Preview approval.
Most projects should integrate Configure into an existing agent: add hosted Link or a Personalization entry in the browser, send the configure:linked token to your backend, read the profile, expose Configure tools, and commit after read-backed turns. Use the packaged template only when you want a fresh Configure-backed chat shell.
Install and setup:
npx configure setup
npm install configureChoose For my users when adding Configure to a product you already ship. Choose your existing agent handle at setup; register a new handle only for a fresh agent shell. Setup opens Configure in your browser. If your account is not approved yet, it will submit or confirm your access request and stop without writing credentials. After approval, setup writes CONFIGURE_API_KEY, CONFIGURE_PUBLISHABLE_KEY, and CONFIGURE_AGENT to .env. If those three values already exist, reuse them and skip setup.
The public server-side SDK shape is:
import { Configure } from "configure";
const configure = new Configure({
apiKey: process.env.CONFIGURE_API_KEY,
agent: process.env.CONFIGURE_AGENT,
});
const profile = configure.profile({ token });
// Patch your EXISTING model loop. Expose Configure tools alongside your own,
// then route configure_* calls to Configure. profile.tools() is Anthropic-native
// ({ name, description, input_schema }); wrap with toOpenAIFunctions() for OpenAI.
// executeTool accepts { name, arguments } or { name, input }.
const tools = [...yourTools, ...profile.tools()];
const dispatch = (toolCall) =>
toolCall.name.startsWith("configure_")
? profile.executeTool(toolCall)
: executeYourTool(toolCall);
const response = await runYourModelLoop({ messages, tools, dispatch });
// Write bounded runtime memory after a read-backed turn.
await profile.commit({ memories: response.memoryCandidates, messages, response });Concrete OpenAI and Anthropic loops: https://docs.configure.dev/guides/tool-calling.
Verify the wiring without a model — execute the read tool directly. When the model calls configure_profile_read in your loop, that is the same dispatch:
const result = await profile.executeTool({
name: "configure_profile_read",
arguments: { sections: ["identity", "summary", "preferences", "imports"] },
});For app-local users that have not linked a Configure identity yet, pass your stable user identifier as externalId:
const profile = configure.profile({ externalId: "customer-123" });baseUrl is only for internal staging/local development and advanced deployments; it should not appear in the normal production path.
Default model tools are only:
configure_profile_readconfigure_profile_searchconfigure_profile_remember
profile.search() returns compact attributed hits by default. Compact hits omit raw CFS paths and provenance; pass detail: "full" when an inspector or admin flow needs safe metadata such as path, markers, provenance, and updated_at.
Use sections: ["imports"] or profile.search({ query: "*", source: "chatgpt" }) for user-directed ChatGPT/Claude/etc. imported memories. Use integrations for connected tools such as Gmail, Calendar, Drive, and Notion.
Connector-backed tools are enabled explicitly:
profile.tools({
connectors: ["gmail", "calendar", "drive", "notion"],
actions: ["email.send", "calendar.create_event"],
});Raw file path access is advanced and lives under configure.files.*. Raw agent filesystem APIs are not part of the public default SDK shape.
Bulk historical/onboarding backfill is separate from runtime profile.commit():
const job = await configure.importProfiles({
mode: "backfill",
users: [
{
externalId: "customer-123",
profile: { preferences: ["Prefers concise replies."] },
conversations: [{
id: "thread-1",
messages: [{ role: "user", content: "I usually fly out of SFO." }],
}],
},
],
});
const status = await configure.importJobs.get(job.id);Import is server-side only, requires an sk_ key, and is not exposed as a model-facing tool.
Browser linking and components
Production browser integrations should use the hosted script:
<script src="https://configure.dev/js/configure.js"></script>Configure.link() handles user-present identity, seeding, consent, iframe isolation, resizing, and the configure:linked event. The host sends the returned agent-scoped token to its backend, then the backend uses configure.profile({ token }).
For chat inputs, Configure.personalizationButton() renders a compact + menu entry with the canonical Personalization toggle. The entry should trigger Configure, while linkEl mounts Configure Link in a dismissible inline chat panel. Let the panel span the assistant message lane (width: min(100%, var(--chat-max, 640px))) and do not cap the host at 420px or mount it inside the composer row. This is the default placement for chat products — not a settings page or a standalone chat-bar button. The onEvent callback exposes the agent-scoped token at event.payload.token; send only that token to your backend:
Configure.personalizationButton({
el: "#configure-entry",
linkEl: "#configure-link-host",
publishableKey: "pk_...",
agent: "your-agent",
agentName: "Your Agent",
font: "Inter, -apple-system, BlinkMacSystemFont, sans-serif",
onImage: () => openImagePicker(),
onFile: () => openFilePicker(),
onEvent(event) {
if (event.type === "configure:personalization-open") {
showInlineConfigurePanel();
return;
}
if (event.type === "configure:linked") {
hideInlineConfigurePanel();
fetch("/api/configure/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: event.payload.token }),
});
}
},
});Images and Files stay host-owned; the helper also emits configure:image-select and configure:file-select. (The declarative data-configure-link trigger instead exposes the token at event.detail.token — use it only for settings pages or static buttons.)
If your chat UI already has an inline integrations list instead of a + menu, render Configure as a rounded lockup button:
Configure.personalizationButton({
el: "#configure-integration",
publishableKey: "pk_...",
agent: "your-agent",
agentName: "Your Agent",
variant: "integration",
});Never expose sk_ keys in browser code. Browser code uses publishable keys (pk_...); the model receives formatted profile context, not Link tokens or user IDs.
When Configure is the auth handoff for your app, use the hosted first-party surface instead of building a custom OTP flow:
Configure.signInWithPopup({
publishableKey: "pk_...",
agent: "your-agent",
returnTo: "https://app.example/auth/configure/callback",
state: "opaque",
fallback: "redirect",
});Allowlist returnTo with POST /v1/auth/sign-in/return-destinations using your sk_ key, then exchange the returned cfgsic_... code server-side with POST /v1/auth/sign-in/exchange. Store the returned agent-scoped token in your app session and pass it into later inline Configure surfaces with Configure.link({ token, userId, ... }) so the user does not repeat OTP. Use the popup path when preserving desktop app context matters; redirect to https://accounts.configure.dev/?pk=...&agent=...&return_to=... for mobile, popup-blocked browsers, or simpler auth routes.
Raw web components are included for local labs and advanced self-hosted surfaces:
import "configure/components";The browser bundle is also packaged at configure/components/cdn, but the hosted script remains the recommended production path.
