Skip to content

Analytics Agents

Status: Current | Last reviewed: 2026-10-07

Analytics Agents use Studio identity, SSO, tenant switching, publication, encrypted integrations and PostgreSQL. The canvas owns chat behavior; immutable dataset releases own preparation. See the CCIQ assessment and user guide. The dataset input contract covers table imports, version carry-forward and the intent tree editor.

Analytics uses the shared Agents repository, filtered with /agents?type=analytics_agents. Its top-level sidebar item is retired. Cards open /agents/{id}/analytics?preview=1; builders can use the separate Edit action. &draft=1 requests a saved draft preview, with existing author checks. Without it, the preview resolves only a published agent available to the current tenant runner. AnalyticsPreview hosts one AnalyticsChat instance while resizing between a maximized surface and the editor-side panel (preview=panel), retaining history, current input and evidence. Copy link preserves mode, never another user's chat. Legacy /analytics?agent={id}&focus=1 redirects to the canonical preview; unselected /analytics redirects to the repository filter. Tenant switches remount previews.

Full analysis adds a scoped SQL/tool loop, operational warehouse snapshots, rich annotations, compiled report hierarchies, versioned memory pages and the ported CallSight composition. The same host serves Preview and the focused app. Built-in cards and selected published catalogues use the shared A2UI component registry; chat inspection actions remain nonterminal and independent of voice surfaces. The simpler metric/search mode remains available when full analysis is disabled.

Use the question and result parity contract for the acceptance scope. Successful requests, matching contact counts and a ported renderer do not alone establish question/result parity.

Enable and run

Apply migrations 068 through 072 through the normal forward migration process. The city migration runner includes preparation, immutable analysis snapshots, report jobs and briefing caches. Never reset a populated database for this feature.

FEATURE_ANALYTICS_AGENTS=true
ANALYTICS_WORKER_CONCURRENCY=4

The runtime flag defaults off and requires the parent Agents capability. It controls both the server and Studio's creation menus, filters and Home portfolio; disabled Analytics agents are omitted from lists/direct reads and their editor and API routes return 404. NEXT_PUBLIC_FEATURE_ANALYTICS_AGENTS is no longer used: build-time values cannot enable a feature in a destination environment. Restart ai-manager and the worker after changing their runtime flag; no frontend rebuild is needed. Scene agents use the separate FEATURE_SCENE_AGENTS opt-in. Worker concurrency is 1–16; the default is four leased jobs in parallel.

cd apps/ai-manager
npm run analytics:worker
# One job for an operational check:
npm run analytics:worker -- --once

The worker uses the normal database, encrypted-integration and assets-store environment (STORAGE_*, STORAGE_BUCKET_ASSETS). PostgreSQL needs pgvector. Set ANALYTICS_PYTHON to a Python environment with the shared libs/pii, libs/transcription, HTTP-client and provider dependencies. The dev launcher uses apps/async-agent/.venv/bin/python and installs the pinned dependencies in apps/ai-manager/analytics_runtime/requirements.txt when needed. Both the chat server and worker require this interpreter. The fixed bridge imports these shared libraries from this checkout; it never executes uploaded code.

Vanguard has the runtime flag and concurrency 16 enabled locally. The main Overmind analytics-worker service is running. Restart it after worker code changes; the worker does not hot reload. The chat server uses Next development reload. After changing shared configuration schemas, restart both ai-manager and analytics-worker: a stale worker can reject a briefing configuration queued by the newer server. Failed briefings show Retry briefing. That action retries only the current authorized failed cache entry; it preserves pending/ready work.

For container environments, build apps/ai-manager/Dockerfile with --target analytics-worker for the queue consumer and the normal runner for Studio. Both include Python 3.12, pinned runtime requirements and shared transcription/PII libraries. Set FEATURE_ANALYTICS_AGENTS=true at runtime in Studio and its Analytics worker. Leave it unset in other deployments to keep Analytics off. ANALYTICS_SHARED_ROOT points to packaged shared libraries; ANALYTICS_PYTHON points to the packaged interpreter. Supply the same DB, encryption, storage and integration environment to the worker. This change packages the services; it does not deploy other environments.

Prompts and model choices

The migration retains the original response-composition prompt and briefing addendum, with explicit adaptations for Studio. It does not retain every original model choice.

Stage Original CCIQ Vanguard Analytics configuration
Chat and briefing Source default us.anthropic.claude-sonnet-4-20250514-v1:0 gpt-5.4, low reasoning; Analysis → Live analyst / Advanced reasoning effort
Native annotation Imported v7 artifacts identify Sonnet 4.5 and convintel.annotation.v4.taxonomy.cciq.driver_taxonomy.v1 gpt-4.1-mini; Preparation → Annotations / Model / Full prompt
Native report and memory narrative Source Bedrock compiler; imported artifact provenance is preserved gpt-4.1-mini; Preparation → Prepared insights / Model / Full prompts
Transcript embeddings Source default amazon.titan-embed-text-v2:0 text-embedding-3-small, 512 dimensions; Preparation → Semantic search / Model / Vector size

Imported reports and annotations are preserved outputs, not silently regenerated with these new models. Changing response settings takes effect after Save/Publish for new chats. Changing offline settings requires a new preparation/report build; an existing release keeps its models, dimensions and prompt provenance.

apps/ai-manager/analytics_runtime/system-prompt.txt retains the first 664 lines of the source prompt. analysis-chat.ts replaces the static AWS warehouse section with the authorized schema, domain vocabulary, exact comparison windows and metric conventions; it also adapts the introductory domain wording. analytics_runtime/briefing-prompt.txt is the original briefing addendum. The full analyst, briefing and review task prompts are editable in Analysis. GET /api/analytics/prompts serves the versioned defaults to authorized builders. Annotation defaults live in prompt-defaults.ts; the exact ported trend/memory templates live in analytics_runtime/{trend,memory}-prompt.txt. Preparation exposes those full templates plus separate trend and memory model bindings. Template placeholders are substituted from compiler data without evaluating code. Basic mode has independently configurable planner and grounded-answer models and prompts. Runtime scope, tool and output contracts remain mandatory.

Native report prompt/formatting functions are ported in analytics_runtime/compiler_format.py; dataset-wide memory synthesis is adapted in lib/analytics/report-compiler.ts. Annotation instructions in lib/analytics/compilers.ts are a Studio structured-output prompt implementing the richer annotation contract, not a verbatim copy of the source prompt.

Review answers against evidence adds one model iteration to check numbers, rankings, comparisons and causal wording. It is a quality/latency control, not a guarantee that every generated sentence is correct. Advanced composition settings expose budgets and tools. provider-client.ts adapts the shared Analytics loop to Bedrock Converse and Vertex GenerateContent; OpenAI uses the Responses SDK. Credentials resolve exclusively from the selected tenant integration. Tool-result history, Bedrock reasoning blocks and Gemini thought signatures survive provider turns. Structured tasks use a forced result tool; compiler outputs still undergo local Zod validation. Bedrock uses the SDK SigV4 signer for encoded model paths. Task models can differ for analyst, review, briefing, annotation, trend and memory synthesis.

Embeddings support OpenAI text-embedding-3, Bedrock Titan v2 and implemented Vertex text embedding families. model-config.ts is the adapter/size catalogue; profile validation and actual returned-vector checks enforce supported sizes. Vertex uses distinct RETRIEVAL_DOCUMENT and RETRIEVAL_QUERY tasks. Cloud embedding batches reserve one request per text; OpenAI reserves one batched request. Integration/model permissions remain prerequisites; selecting a model does not provision cloud access.

Preparation and serving

flowchart LR
  Upload[Bulk transcripts, workbook or audio] --> Objects[Encrypted Studio assets]
  Upload --> Manifest[Durable file manifest]
  Manifest --> Worker[Leased preparation worker]
  Objects --> Worker
  Worker --> STT[Shared transcription and PII]
  STT --> Turns[Private normalized turns]
  Turns --> Annotation[Annotation compiler]
  Annotation --> Embedding[Embedding compiler]
  Embedding --> Ready[Complete immutable release]
  Ready --> PG[PostgreSQL full-text and pgvector]
  Canvas[Studio canvas] --> Version[Agent version]
  Version --> Chat[Preview or focused Analytics app]
  Chat --> PG
  Chat --> Model[Tenant response model]
  Chat --> History[Private history and citations]

Each upload creates an idempotent manifest, then streams each file into the shared assets store. A random AES-256-GCM data key encrypts each source and is wrapped by Studio's managed encryption helper, including KMS when configured. Object keys contain tenant/release/file IDs, not original names. Sources have no public download API. Only authenticated, complete plaintext is handed to the fixed preprocessing bridge. Credentials travel through stdin and are not placed in command arguments, inherited cloud environment variables or provider logs.

A worker claims a file or conversation using short transactions, SKIP LOCKED, a lease token and heartbeats. Provider work happens outside claim transactions. File normalization is atomic inside its still-private release. Annotation and embedding batches checkpoint independently; retries preserve completed work. 429/5xx/connection failures and invalid annotation contracts retry with backoff, up to five job attempts. Permanent failures stop the release; Retry incomplete stages resumes it explicitly. Request budgets count attempts and never reset on retry. A new build is required to change the immutable profile or its budget.

Cancellation and checkpoint writes lock/recheck the release. A release becomes ready only after every file and compile item completes. Incomplete releases are never selected by chat. Existing sessions pin their release and published agent version. Rebuilds reuse retained encrypted source but clear normalization markers; copying a prior build's checkpoint would skip the new release's data.

Table Contents
analytics_datasets Tenant identity, external source ID and real/synthetic classification
analytics_releases Immutable profile/input manifest, status, budget consumption and source digest
analytics_ingestion_files Encrypted source reference, SHA-256, file lease and provenance
analytics_compile_items Per-conversation annotation/embedding checkpoints and retries
analytics_conversations, analytics_turns Prepared IDs, times, channels, roles, duration and full-text vectors
analytics_annotations Model findings, evidence ordinals, model and profile hash
analytics_chunks Prepared text chunks and model/dimension-specific pgvector vectors
analytics_sessions, analytics_answers Private pinned sessions, applied filters, answers and citations
analytics_analysis_sets, analytics_relation_schemas, analytics_relation_rows Immutable typed operational snapshots
analytics_artifact_bodies, analytics_session_state Compiled report bodies and private tool/attachment history
analytics_report_jobs, analytics_briefings Durable hierarchy jobs and scheduled briefing caches

New tables have forced tenant RLS and compound foreign keys. Studio's service role bypasses RLS, so every application query also has explicit tenant/release predicates. Workers establish tenant context before the shared secret resolver; a globally privileged database connection alone does not authorize credentials.

Configurable preparation

Setting Effect
Canonical or Contact Lens JSON Adapter for JSON/JSONL; XLSX and audio are detected separately
Transcription integration, language, diarization, role map Shared Deepgram/AWS/Azure/Google adapters; unmapped speakers stay unknown
Rules, managed PII, or redacted-source attestation Runs before searchable rows or model requests; tenant policy may tighten it
Annotation model, instructions and driver taxonomy Evidence-grounded summaries, primary driver, sentiment and outcome
Embedding model, dimensions, chunk size and overlap Covers every indexed turn, including the tail of long turns
Dictionary and speaker roles English/simple full-text dictionary and retrieval scope
Request budget and source retention Bounds provider requests; retained encrypted sources enable rebuilds

Rules detect structured identifiers such as email, phone and payment data; managed detection supports names and addresses. Audio cannot use attestation. Managed detection uses overlapping windows and unions overlapping spans so an identifier crossing a window or turn boundary is not partially retained. Integrations must enable the selected speech-to-text, PII or model capability. A required self-hosted tenant PII detector is currently unsupported and blocks ingestion instead of falling back. Raw source is encrypted transient input; warehouse/model boundaries receive prepared text. With retention off, original source references are removed after normalization; shared retained rebuild references prevent premature object deletion. There is no source-purge scheduler or user-facing dataset deletion yet.

Uploads produce immutable complete snapshots. A new manifest may include sourceReleaseId and removeFileIds: retained encrypted source references are copied into the new release, omissions are removed there, and uploaded files are added. Ownership, matching dataset, terminal source state, retained objects, unique filenames and combined limits are checked before creation. Old snapshots are untouched. At most 10,000 files, 100 MiB/file, 2 GiB/batch and ten active batches/tenant. One parsed file allows 20,000 conversations and 200,000 turns; a conversation allows 2,000 turns and each turn 16,000 characters. XLSX expansion is bounded. Uploads can resume after reselecting the same files; completed files are skipped. Concurrent writes to one file fail with 409. Source inventory/checkpoint changes are not silently merged.

The legacy /datasets POST still accepts its original 5 MiB pre-redacted pilot format. It cannot bypass a tenant policy requiring automated redaction; use /ingestions for those tenants or any new compiler features.

Source fidelity

Canonical input has id, optional channel/startedAt, and ordered turns containing role, text and optional startMs. Dates remain unknown when absent. Contact Lens imports preserve contact IDs, CCIQ started_at, original channel, duration and synthetic provenance. Empty non-speech events are counted in source_metadata.omittedEmptyTurns, not turned into invented speech.

Netomi workbook import uses the existing parser, including swapped transcript and summary columns. It does not import evaluation labels, infer dates, or use workbook summaries as model findings. Migrating existing Contact Lens exports preserves their original IDs and declared synthetic timing. Synthetic and real sources must use separate datasets; FNOL is real-source demo material despite its historical S3 prefix containing the word synthetic.

CSV maps one turn per row using a required conversation ID/text column and optional role, start time, channel and offset columns. Parsing supports quoted multiline fields and rejects duplicate headers, conflicting metadata and malformed rows. Conversation IDs are validated across files by the normal compiler. GET /datasets/{id}/conversations provides tenant-scoped, paged prepared transcript previews; the source inventory reports retained status and per-file conversation counts. Migration 072 permits CSV source manifests.

Chat, search and app experience

Author at /agents/{id}/analytics. Call Drivers is the first Analytics type; older agents default to it. The wizard and settings expose a Type dropdown. See types and canvas for the type registry, per-type configuration editors and fixed preset layout.

Dataset operations live in a modal. Preview flushes the collaborative draft and opens maximized; minimize changes layout without remounting the chat. Direct draft preview URLs load the saved configuration without mutating it. Published preview routes do not join an editing room or read a draft. The preview header retains chat controls, copy link, edit/back navigation, and tenant/account controls when maximized. Feature flags and all analytical API authorization remain unchanged.

AnalyticsEditor uses the shared collaboration room, bridge, presence and save indicator. Both pipeline converters use an Analytics Y.Map with recursive object fields, so edits to different settings merge independently; vocabulary arrays are atomic. Legacy Analytics values in the misc map are readable and migrate on reconciliation. The gateway hydrates a published Analytics config when its draft is initially empty. Drafts may contain incomplete settings; Preview/Publish validate them, flush collaboration and confirm the persisted content. Test through the city nginx origin, because :3001 bypasses the collaboration WebSocket.

Agent versions own the Analytics type, preparation drafts, data selection, live models/prompts, tools, composition and branding. Prepared releases freeze their compiler profiles. Every relative-date path uses today UTC; legacy referenceDate is accepted for compatibility but ignored. Explicit historical dates remain available. All tenant RunAgents users can consume published Analytics agents; ManageAgents controls authoring. Legacy audience lists are ignored. Branding copies existing surface templates and supports per-agent logo/icon/palette values.

Keyword counts cover all indexed matches, never a top-k estimate. Exact volume, annotation and outcome counts cover the displayed date/channel/annotation scope; keyword matching is identified separately. Unknown dates/outcomes remain unknown. Annotations are explicitly model findings, not verified operational facts. Evidence ordering favors different conversations before additional turns from the same one. Overview evidence prioritizes the annotation's supporting turns over introductory greetings. Explicit requests to show one conversation select one authorized hit and retrieve bounded, ordered excerpts from that contact; they cannot mix multiple calls into a purported single example. Opening a transcript shows all prepared roles; role filtering is a retrieval setting, not a data ACL.

Semantic queries use the released embedding model, profile and dimensions. Exact cosine search applies tenant, release, date, channel, role and annotation filters before ranking. Basic hybrid search fuses keyword/semantic ranks; full analysis can additionally constrain a semantic search to lexical topic matches inside the authorized candidate set. No global ANN top-k can exclude an authorized tenant's evidence. This is suited to demo-scale corpora; larger deployments should benchmark release-partitioned ANN indexes, warehouse partitioning and compiled rollups before scaling.

The selected provider supplies bounded structured planning/explanation; annotations use a taxonomy-specific schema and valid turn bounds. Basic mode does not accept model SQL. Full analysis accepts one guarded SELECT/CTE over registered typed relations; it cannot change data bindings, perform writes, call arbitrary functions or resolve credentials. Chat query embeddings have a four-second timeout; other model calls allow 20 seconds. Chat falls back visibly to keyword evidence or warehouse results when a provider is unavailable. Date output is constrained to calendar dates. Grouped citations are validated and expanded into clickable references. Answers use Studio's Markdown renderer, with remote images and model-generated external links disabled. Provider-reported annotation/chat/embedding token usage uses existing costing events (embedding product embedding). Unknown pricing is not a zero-cost estimate. Transcription and PII request counts are included in budgets; their provider costs are not yet metered by this worker. The existing tenant governance and model-deny rules apply.

Publication/tenant permission checks, session ownership and current data bindings gate history and evidence on every request. Tenant authors administer datasets; there are no additional row-level business grants beyond tenant/release isolation.

Migration and verification

npm run analytics:migrate-cciq -- SPEC.json CHECKPOINT.json [--inspect] is a trusted operator command using the normal Studio environment. Its specification contains tenant slug, an active authorized actor username, source integration ID, bucket/region and datasets (externalId, name, redacted prefix, synthetic, preparation, optional duplicatePolicy). Credentials remain in encrypted integrations. It paginates the entire source inventory, uploads six files concurrently through shared storage, records provenance and checkpoints resumably. Keep its checkpoint private. It writes only to Studio; original CCIQ objects remain unchanged. Duplicate contact IDs fail by default. Explicit duplicatePolicy: "latest" inventories contact IDs before upload, selects the newest source object for each ID (lexical key breaks timestamp ties), and reports superseded object counts. Changing the specification or source inventory requires a new checkpoint.

The migration covers FNOL, the original Delta seed, Netomi Delta and the newer CallSight corpus. The original Deloitte/Delta/FlightStar profiles share the CallSight data but become separately configurable Analytics Agents. Brand instructions do not rewrite original evidence. Full analysis also imports original operational/customer/survey tables, annotations, trend and memory bodies, and citation indexes through scripts/migrate-cciq-analysis.ts. This operator adapter reads the original AWS sources with an explicit tenant integration; serving uses PostgreSQL and has no AWS credential dependency. Historical generated reports remain identified as model findings. Original chat sessions are not imported.

The OpenAPI reference includes manifest creation, file upload, progress, start/retry/cancel/rebuild, authoring, published agents, private history, chat and evidence. Publication reuses the existing pipeline version endpoint. Every route uses Studio authentication and the matching agents:manage/agents:run scope.

cd apps/ai-manager
node --import tsx --test lib/analytics/analytics.test.ts lib/analytics/preparation.test.ts
# Only an isolated local validation database, with 068–071 applied:
ANALYTICS_TEST_DATABASE_URL=... node --import tsx --test lib/analytics/*.integration.test.ts
npm run typecheck
# Fixed bridge privacy/workbook regressions:
"$ANALYTICS_PYTHON" scripts/analytics-preprocess.test.py

Tests cover tenant isolation, authenticated encrypted storage, source redaction, idempotency, immutable rebuilds, failed-stage recovery, model/evidence contracts, request budgets, source retention and retrieval. Browser tests exercise normal Studio authentication, upload, canvas controls, preview, publication, evidence, private history and tenant-reader permissions. Vanguard additionally exercises real transcription, annotation and embedding integrations using synthetic fixtures.

Current validation and limits

See executed validation for source revision, dataset coverage, side-by-side results, browser checks and commands. The earlier transcript-only benchmark is superseded: its shorter answers were not equivalent work and must not be quoted as full-analysis performance.

Full analysis uses bounded read-only SQL translated from Trino to PostgreSQL. CTEs, joins and arrays are supported; writes, unregistered relations, arbitrary functions, recursion and lock clauses are rejected. Query time is capped at ten seconds and returned rows at 5,000. SQL errors use savepoints so the model can repair a query without aborting the entire chat transaction. Cost metering uses a small independent pool to avoid waiting for a connection held by the chat.

Snapshots support up to 50 typed relations and 100 MiB warehouse upload bodies. They remain a portable PostgreSQL implementation, not a replacement for a large columnar warehouse. At larger scales, implement a warehouse adapter and benchmark its joins and vector filters before changing those bounds. Runtime models support OpenAI, Bedrock and Vertex through tenant integrations; shared transcription/redaction retain their existing providers. GCP DLP byte offsets are converted to Unicode character offsets before redaction. Response components and briefings can use selected published catalogue versions. The focused app uses Studio SSO and tenant access, requiring no second identity system or standalone deployment.