Reference

SDK Module Map & Data Flow

← Back to System Internals Reference

This section is the source-of-truth map of the SDK's internals: how a call flows from a typed method to the right backend, and the routing/data-flow rules README doesn't cover.

Two entry points, one shared core

Branch security on the minted Token, never on inspectKs(realKs).kind. The public inspectKs export (@kaltura/intelligent-agents/management, src/management/ks-inspect.js) decodes only a KSv2 token's plaintext header. It reliably returns {partnerId}. But a real encrypted KS has its privileges AES-encrypted, so inspectKs returns kind:'opaque', disableEntitlement:null, encrypted:true. kind/disableEntitlement are populated only for unencrypted test tokens. To decide what a token may do, read the .kind of the minted Token object instead. It records what it was minted with: admin/conversation/agent/widget. Don't use inspectKs of an opaque production KS for that decision.

Management modules (what each does, where it writes)

Module (src/management/) Exposes Backend the writes hit
intellects.js Intellects: DTO CRUD (add/get/update/delete), prompt authoring (setPrompts/previewPrompt/snapshot/restore/diffSnapshots), capabilities (getCapabilities/setCapability/setCapabilities/resolveCapabilities), setClientVariablesEnabled. Mounts secrets (tools are a separate top-level resource; see tools.js). the brain v1/intellect/*
intellect-config.js IntellectConfig (mgmt.intellectConfig): the ONE shared patch(configId, patch|fn, ks) primitive + typed field setters incl. setToolIds (the intellect-side tool_ids reference list), setSkillIds, setThreadStartTools, setModelConfiguration, setOpeningPhrase, setAvatarSummaryConfig + describe() (every EDITABLE_FIELDS value). Exports the closed enums SKILL_MODES, MODEL_IDS, THINKING_LEVELS, SUMMARY_CONTENT_TYPES. buildUserPropertiesForms. the brain v1/intellect/update (read-modify-write, full-replace dicts; tool_ids is a plain array write)
set-forced-language.js setForcedLanguage (mgmt.setForcedLanguage): forces the reply language by writing force_language on the intellect (via intellectConfig.patch; the backend enforces it at runtime) and the agent's asr.language (via agents.update) in one idempotent call. Strips the marker block older SDK versions appended to base_directive. LANGUAGE_NAMES (ISO 639-1 code → display name). the brain v1/intellect/update + Agentic API agent/update
capabilities.js CAPABILITIES/CAPABILITY_STATE/CAPABILITY_DEFAULTS/CAPABILITY_INFO, assertCapability/assertCapabilityState/validateCapabilities, resolveCapabilities (pure layered resolver), mergeCapabilityWrite. Re-exported from BOTH entry points. pure, no network
tools.js tools.api/csv/code builders + tools.client (authors a native, silent client-side command tool with no server-side call, requires kaltura_genie_experiences:'off'; see Client-Side Commands) + tools.clientToolReadiness + tools.validate, class Tools (mgmt.tools: add/get/list/update/remove over the standalone Tool entity), applyResponseMapping. the brain v1/tool/* (partner-level entity CRUD, not intellect/update; link via intellectConfig.setToolIds's tool_ids)
skills.js Skills (mgmt.skills: add/get/update/list/delete over the standalone, partner-level Skill entity; delete checks for intellects still referencing the id before acting). the brain v1/skill/* (partner-level entity CRUD, not intellect/update; link via intellectConfig.setSkillIds's skill_ids)
secrets.js IntellectSecrets (mgmt.intellects.secrets: listNames/has/set/remove/replaceAll/validate), validateSecretRefs. Write-only values; name-only read contract (no redact() reliance). the brain v1/intellect/update config.secrets (mask-and-keep merge)
prompt-lint.js pure: lintPrompts/validatePromptVars/lintGlossary/assembleSystemPrompt/SYS_VARS. Client-side prompt-preview replica (author layer only). pure, no network
conversations.js Conversations (stream/send, assertRequestVars), Threads/Messages/Feedback/Followups, Knowledge (addRecord + knowledge_ids linkage, ungated; uploadDocument, createCategory/findOrCreateCategory (plain entry containers), corpusStatus, getLinkage, setEnabled, search, isIndexed, entryStatus). the brain's assistant/converse (converse); the brain's v1/knowledge/add + intellect knowledge_ids (ungated); OVP category/*+upload (containers)
lifecycle.js Lifecycle (mgmt.lifecycle: create/get/update/delete/list over event-driven rules {eventType, objectType, eventConditions, action}, plus read-only match/listObjects/listEvents/describeFields). A rule's action can trigger an insight extraction, an insight email, or the built-in lead-capture insight. the Agentic API's lifecycle/*
insight-settings.js InsightSettings (mgmt.insightSettings: create/get/update/delete/list over reusable {key, title, prompt, valueType, status} insight definitions). Referenced by a lifecycle rule's action.insightSettingsIds, not embedded in the rule itself. the Agentic API's insight-settings/*
provision.js provision(): the agent factory; optional knowledge/tools/capabilities blocks layer after the core create (tools creates each Tool entity via mgmt.tools.add, then links the successful ids in one intellectConfig.setToolIds write). both hosts

The top-level headless converse surface lives on the Management class itself: converse(configId, message, opts?, ks?) (AsyncGenerator over conversations.stream) and converseOnce(...) (delegates to conversations.send). Both auto-mint a conversation token from configId when ks is omitted, so the admin secret never leaves the server.

opts carries {threadId, sse, model_type, force_experience, request_vars, capabilities, recoverFromSpiral}. assertRequestVars rejects reserved keys and non-scalar values before the wire.

opts.capabilities is a per-message {name:state} override, validated client-side. But the server-side DISABLED veto still wins: a stored or env-disabled capability cannot be turned on per message. For example, converse(cfg, msg, {capabilities:{use_web_search:'on'}}) is honored only if use_web_search is not disabled by a stored layer.

opts.recoverFromSpiral:true on conversations.send/converseOnce sends one same-thread nudge retry (SPIRAL_RECOVERY_PREFIX) when the first attempt comes back spiralStopped:true with empty text. See stream.js's collectConverse entry above for what it's recovering from.

Scope-guard timing on the streaming path. conversations.stream(...) is an async generator, so its assertConversation(ks) scope check fires on the first .next()/iteration, not at call time. const g = k.conversations.stream(opts, adminKs) without iterating gets no guard yet. This is despite the client's "before any network call" framing, which holds for the non-generator methods. For eager scope validation, use conversations.send(...)/converseOnce(...) instead: they assert the token kind synchronously before returning. The non-generator reads (conversations.status, all agents/avatars/catalog calls) guard at call time, as documented.

resolveCapabilities return shape (the 16 names are nested, not top-level)

resolveCapabilities(layers) (src/management/capabilities.js) returns a two-key object, { capabilities, _meta }, so Object.keys(result).length === 2. The 16 AssistantCapability states live under .capabilities, keyed by name, NOT at the top level:

const { capabilities, _meta } = k.intellects.resolveCapabilities({
  partnerConfig: stored,                       // from intellects.getCapabilities
  request: { use_web_search: 'off' },          // per-turn override to model
});
capabilities.avatar.state;          // 'on' | 'off' | 'disabled'
capabilities.avatar.resolvedFrom;   // which layer won

Each per-name entry is { state, resolvedFrom, vetoed, layers }:

A freshly created intellect returns an empty capabilities {} from getCapabilities (nothing stored yet), so every name then resolves from the env/default layer until you setCapability/setCapabilities.

Experience GenUI layer

src/experience/genui/ turns brain unisphere-tool segments into framework-agnostic render descriptors:

session.js wires the guardrail gate. Each agent_raw_text delta is classified by classifyAgentAction (wire.js, reading seg.metadata.runtimeName/widgetName plus the adapter-normalized seg.type with -tool stripped). When a capability policy or onAgentAction hook is present, the delta runs through _gateAgentAction before emit('brainSegment', d). This is default-allow, so existing nav/GenUI flows are untouched; a veto emits agentActionDenied plus an agent.action.deny audit event. Presenter exposes covered/questions/lastNav ({target, reason, at}). session.micEnabled is a read getter.

Routing rule: the intellect DTO is the whole writable surface

The intellect DTO (v1/intellect/*) is the one real door for every writable field: prompts, base_directive, glossary, capabilities, tool_ids, skill_ids, thread_start_tools, secrets, user_properties_forms, mcp_servers, allow_client_variables, knowledge_ids, avatar_summary_config, force_language, opening_phrase, model_configuration, name/description/tags/status. It's writable with a partner admin KS, ungated.

Knowledge linkage rides this same door. First call POST /v1/knowledge/add on the brain host, which returns an {id,...} record. Then pass the returned id as knowledge_ids in the intellect create/update DTO. Linkage plus use_knowledge_base:'on' persist with no separate linking call.

It is a model_fields_set PATCH, so omitted top-level fields are preserved. But capabilities/secrets are full-replace sub-dicts, so the SDK read-merge-writes them, via mergeCapabilityWrite or the secrets mask-and-keep guard. IntellectConfig.patch is the one place that logic lives.

EDITABLE_FIELDS in intellect-config.js is the exact list of keys v1/intellect/get echoes and v1/intellect/update accepts for a partner admin KS. patch() rejects any other key before the network call, and describe() returns exactly these keys. When adding a field setter, first confirm the key round-trips through intellect/update and intellect/get with a partner admin KS. Then add it to EDITABLE_FIELDS.

Known limits

The SDK's own node:test suite (test/) exercises every one of these surfaces against the real backend and against injected fakes. See README.md for the full command list.

Doc Covers
System Internals Reference · Resilience and Failure Handling Failure modes, TURN/relay, and the tool-call-spiral breaker touched on above
System Internals Reference Back to the index
Click to talk with Nova — she knows this whole SDK.
Nova AI assistant — knows this whole site

Reloading starts a fresh chat. “New conversation” does the same without leaving the drawer.