Build a cited research assistant with OpenAI web and file search
Build a bounded research service that combines current web evidence with a private vector store, renders clickable citations, exposes every consulted source, limits retrieval, records cost, and refuses unsupported conclusions.
Deliver a runnable research assistant whose evidence can be inspected independently, whose private and public sources remain distinguishable, and whose tool access cannot silently expand into external writes or unlimited research spend.
- Node.js 22.22.2
- OpenAI Node SDK 7.1.0
- OpenAI Responses API 2026-07-29
- Research model gpt-5.5
- Dedicated OpenAI project Use a project with a bounded test budget, web-search access, file-search access, and a server-side key that is not shared with unrelated workloads.
test -n "$OPENAI_API_KEY" && echo OPENAI_KEY_PRESENT - Reviewed knowledge corpus Prepare non-secret source files whose ownership, retention, classification, and deletion rules are known before uploading them to a vector store.
find corpus -type f -maxdepth 2 -print - Source and decision policy Define allowed public domains, minimum evidence, citation UX, prohibited topics, human approval boundaries, and a maximum cost and duration per research request.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A Node.js research command that accepts one question, searches an approved private vector store and a restricted set of current web domains, and produces a brief with evidence, inference, uncertainty, and unresolved questions clearly separated.
- A source ledger containing inline URL and file citations, the complete list of web sources consulted by the tool, response and usage identifiers, and enough location metadata for the interface to make every citation visibly clickable.
- A retrieval boundary that limits file-search results, web-search context, output size, domains, request size, concurrency, and per-user budget without adding any external write-capable tool.
- A repeatable evaluation and release gate that checks citation presence, source entailment, private-corpus access control, prompt-injection resistance, latency, spend, refusal behavior, and corpus cleanup.
- Every published factual paragraph has at least one inspectable citation, while unsupported claims are omitted or labeled as unresolved instead of being presented with decorative references.
- The operator can distinguish URLs cited inline from the broader set of URLs consulted during web search and can inspect retrieved private chunks without exposing them to unauthorized users.
- Changing allowed domains, vector-store contents, model, retrieval count, or reasoning effort creates an explicit evaluated revision rather than an invisible behavioral change.
- Removing a document from the approved corpus and deleting obsolete vector-store state prevents it from appearing in future research runs after the deletion workflow completes.
Architecture
How the parts fit together
A trusted ingestion job uploads reviewed files to one purpose-specific vector store and records a local manifest. The application validates the user question and domain policy, then calls Responses with only read-only web_search and file_search tools. The model decides when to search within these boundaries. The application parses message annotations, file-search results, complete web-search sources, response usage, and refusal or incomplete status into a stable result contract. The UI renders answer text without HTML interpretation and turns only validated citation ranges into visible links. Evaluation samples the cited passage and source metadata rather than treating a syntactically valid annotation as proof.
- An administrator approves a file, records its checksum and policy metadata, uploads it, attaches it to the dedicated vector store, and waits until processing completes.
- An authenticated user submits a bounded question; the application resolves the correct vector store and allowed-domain policy server-side.
- Responses runs file and web searches, returns an answer message, inline annotations, optional included retrieval results, the complete consulted-source list, and usage.
- The application rejects missing output, stores only policy-approved metadata, and returns a normalized answer and source ledger to the UI.
- The UI renders citations as obvious links and labels private-file evidence separately; a reviewer can open the exact source before acting on the answer.
- Offline evaluations and deletion drills gate every model, prompt, corpus, retrieval, or domain-policy revision.
Assumptions
- The private corpus contains documents the application is authorized to send to the configured OpenAI project, and users are separately authorized before seeing retrieved content.
- Allowed domains are maintained as a server-side policy. User input can narrow the policy for a request but cannot add unreviewed domains or enable unrestricted live browsing.
- The selected model and tool combination is available in the project, and current pricing and rate limits are checked in the dashboard before release.
- The product can show citations as visible links, preserve source titles and locations, and clearly distinguish evidence from model-generated interpretation.
- The team owns a representative research evaluation set with expected sources, intentionally unanswerable questions, injection attempts, and freshness-sensitive cases.
Key concepts
- URL citation
- A typed annotation that identifies a cited URL, title, and character range in generated output. It is evidence metadata, not an automatic guarantee that the claim is entailed.
- File citation
- An annotation linking generated text to a file in the configured knowledge base. Authorization must still be enforced by the application.
- Consulted sources
- The sources list returned from web-search actions, including URLs used during research even when they do not become inline citations.
- Vector store
- A managed knowledge base that processes uploaded files and supports retrieval for the file_search tool.
- Retrieval budget
- The combined ceiling on search context, number of file results, output tokens, latency, concurrency, and monetary spend for one request.
Before you copy
Values used in this guide
{{allowedDomains}}Comma-separated public domains approved for this assistant's web evidence.
Example: openai.com,nist.gov,ietf.org{{vectorStoreId}}Identifier of the purpose-specific reviewed private knowledge base.
Example: vs_approved_research_corpus{{researchModel}}Evaluated model for multi-source research; re-check availability and behavior before changing.
Example: gpt-5.5Security and production boundaries
- File search is not an authorization layer. Resolve the permitted vector store from the authenticated tenant and role; never accept an arbitrary vector-store ID from the browser.
- Treat retrieved documents and web pages as untrusted data that can contain prompt injection. Instructions in evidence never override the application policy or enable additional tools.
- Do not log raw questions, private chunks, complete answers, API keys, or signed URLs by default. Record response IDs, policy revision, source counts, latency, usage, and sanitized error classes.
- A research assistant remains read-only. Opening tickets, sending mail, editing files, purchasing, or publishing requires a separate authenticated workflow and explicit human approval.
Stop before continuing if
- The application cannot prove which user or tenant is authorized to search the selected vector store.
- Citations are hidden, unclickable, stripped during rendering, or displayed without a distinction between cited and merely consulted sources.
- The assistant can add arbitrary domains, call write-capable tools, or run unbounded research from user-controlled input.
- The corpus includes secrets, prohibited personal data, unclear ownership, or records without a working deletion path.
- The evaluation set shows unsupported cited claims, cross-tenant retrieval, prompt-injection obedience, or unacceptable cost variance.
decision
Freeze the research and evidence contract
Write the answer types, approved domains, corpus authorization, minimum citations, prohibited actions, maximum duration and spend, retention, and escalation rules before enabling either search tool.
Why this step matters
Search quality cannot be evaluated or secured until the product defines what counts as evidence, what may be searched, and when the assistant must abstain.
What to understand
Separate current public facts from internal policy facts because they use different sources and freshness expectations.
Define an unresolved state so missing evidence does not become a polished unsupported answer.
System changes
- Creates a reviewed research policy and evaluation baseline without sending data to the API.
Syntax explained
minimum citations- A product rule checked after generation; it is not guaranteed merely by enabling search.
Policy revision: research-v1 Tools: web_search, file_search (read-only) Minimum citations: 2 External writes: prohibited Per-request budget: approved
Checkpoint: Approve the research contract
Continue whenA reviewer can identify allowed evidence, prohibited tools, budget, retention, and abstention behavior.
Stop whenStop if corpus ownership, user authorization, public domain policy, or the maximum request budget is unknown.
If this step fails
Reviewers disagree about whether an answer is acceptable.
Likely causeNo measurable evidence and abstention rubric exists.
Compare the proposed brief with the written rubric
ResolutionResolve the policy conflict before implementation.
Stop conditions
- Stop if corpus ownership, user authorization, public domain policy, or the maximum request budget is unknown.
config
Create the pinned research project
Create a minimal Node.js project, pin the SDK and validation library, and keep all provider configuration in environment variables.
Why this step matters
A small pinned runtime makes model and tool behavior reproducible and prevents an unrelated dependency upgrade from changing the research release.
What to understand
The API key remains outside source control and browser code.
Package updates are reviewed with the same evaluation set as model and prompt changes.
System changes
- Creates package.json and the local dependency tree.
Syntax explained
openai 7.1.0- Pinned official JavaScript SDK used by the examples and webhook-safe response types.
package.json{
"name": "cited-research-assistant",
"private": true,
"type": "module",
"scripts": {
"start": "node --env-file=.env src/index.mjs",
"check": "node --check src/index.mjs",
"smoke": "node --env-file=.env test/smoke.mjs"
},
"dependencies": {
"openai": "7.1.0",
"zod": "4.4.3"
}
}added 2 packages 0 vulnerabilities OPENAI_API_KEY is loaded by the server only
Checkpoint: Validate the local runtime
Continue whenNode loads the pinned SDK and the tracked tree contains no .env file.
Stop whenStop if a key or private corpus file is tracked, printed, or placed in client-side code.
If this step fails
The SDK cannot be imported.
Likely causeInstallation used a different directory or unsupported Node runtime.
node --versionnpm ls openai
ResolutionRestore Node 22 and reinstall the pinned dependencies.
Security notes
- Add .env, corpus exports, source previews, and generated briefs to .gitignore.
Stop conditions
- Stop if a key or private corpus file is tracked, printed, or placed in client-side code.
command
Create the vector store and ingest reviewed files
Upload only approved files, create one purpose-specific vector store, attach each file, wait for completed processing, and record IDs and checksums in a local manifest.
Why this step matters
File search works only after the knowledge base is processed, while the manifest supplies the ownership, revision, and deletion evidence absent from an opaque ID.
What to understand
Do not upload an entire shared drive merely because retrieval is selective.
Wait for processing and fail the release when any required file is rejected or stale.
System changes
- Creates provider File and vector-store file objects and records their lifecycle metadata.
Syntax explained
purpose-specific vector store- Limits accidental cross-product and cross-tenant retrieval and simplifies deletion.
node --env-file=.env scripts/ingest.mjs corpus/approved-policy.pdffile=file-A1 checksum=sha256:4fa2… status=processed vector_store=vs-approved files=1 failed=0
Checkpoint: Verify corpus processing
node --env-file=.env scripts/ingest.mjs corpus/approved-policy.pdfContinue whenEvery manifest entry has one checksum, provider file ID, vector-store ID, processed state, owner, and review date.
Stop whenStop if files contain unapproved secrets, unsupported personal data, unclear licensing, or cannot be deleted.
If this step fails
The vector-store file remains in progress or fails.
Likely causeThe file type, size, parseability, or provider processing failed.
Inspect file status and sanitized errorValidate the local file before re-upload
ResolutionCorrect or replace the source and create a new manifest revision; never silently omit a required document.
Security notes
- Authorize corpus ingestion separately from research queries and audit every add or delete.
Stop conditions
- Stop if files contain unapproved secrets, unsupported personal data, unclear licensing, or cannot be deleted.
config
Implement bounded web and file research
Call Responses with the evaluated research model, read-only tools, allowed domains, a result limit, explicit reasoning and output bounds, and included retrieval evidence.
Why this step matters
The provider call is the enforcement point for model role, available tools, search scope, retrieval volume, retention, and output cost.
What to understand
Request all web sources and file results needed for audit rather than relying only on rendered text.
Keep external actions impossible by omitting write-capable function tools from the session.
System changes
- Creates the server-side research implementation and sends bounded research requests to OpenAI.
Syntax explained
filters.allowed_domains- Restricts web results to the reviewed server policy.
max_num_results: 8- Bounds file retrieval latency and token cost; evaluate the quality tradeoff.
include- Returns complete web-source metadata and file-search results for inspection.
src/index.mjsimport OpenAI from "openai";
import { z } from "zod";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const request = z.object({
question: z.string().trim().min(10).max(4000),
allowedDomains: z.array(z.string().min(3)).max(20),
});
const input = request.parse({
question: process.argv.slice(2).join(" "),
allowedDomains: process.env.ALLOWED_DOMAINS.split(",").filter(Boolean),
});
const response = await client.responses.create({
model: process.env.OPENAI_MODEL,
reasoning: { effort: "high" },
instructions: [
"Produce a source-cited research brief.",
"Separate evidence, inference, uncertainty, and unresolved questions.",
"Prefer the private corpus for internal policy and current web sources for external facts.",
"Never claim that a citation proves more than the cited passage.",
"Do not call any tool that writes to an external system."
].join(" "),
input: input.question,
tools: [
{
type: "web_search",
search_context_size: "high",
filters: { allowed_domains: input.allowedDomains }
},
{
type: "file_search",
vector_store_ids: [process.env.OPENAI_VECTOR_STORE_ID],
max_num_results: 8
}
],
include: ["web_search_call.action.sources", "file_search_call.results"],
max_output_tokens: 5000,
store: false
});
const message = response.output.find((item) => item.type === "message");
const text = message?.content.find((item) => item.type === "output_text");
if (!text) throw new Error("missing_research_answer");
const citations = (text.annotations ?? []).map((item) => ({
type: item.type,
title: "title" in item ? item.title : undefined,
url: "url" in item ? item.url : undefined,
fileId: "file_id" in item ? item.file_id : undefined,
filename: "filename" in item ? item.filename : undefined,
start: "start_index" in item ? item.start_index : undefined,
end: "end_index" in item ? item.end_index : undefined
}));
const consultedSources = response.output
.filter((item) => item.type === "web_search_call")
.flatMap((item) => item.action?.sources ?? []);
console.log(JSON.stringify({
responseId: response.id,
answer: text.text,
citations,
consultedSources,
usage: response.usage
}, null, 2));{
"responseId": "resp_research_01",
"citations": [{"type":"url_citation","title":"Official guidance"},{"type":"file_citation","filename":"approved-policy.pdf"}],
"consultedSources": [{"url":"https://example.gov/reference"}],
"usage": {"total_tokens": 2840}
}Checkpoint: Inspect one mixed-source response
Continue whenThe normalized payload includes answer text, citation annotations, consulted sources, response ID, and usage.
Stop whenStop if the request exposes an arbitrary vector-store ID, unrestricted domains, a write tool, or raw provider output directly to the browser.
If this step fails
The request returns no message output.
Likely causeThe response was refused, incomplete, failed, or parsed with assumptions about output order.
Inspect response.status and output item typesPreserve the response ID
ResolutionHandle each typed terminal state and show a safe unresolved result instead of indexing into a guessed array.
Security notes
- Validate question length and domain policy before the API call; never interpolate user text into developer policy.
Stop conditions
- Stop if the request exposes an arbitrary vector-store ID, unrestricted domains, a write tool, or raw provider output directly to the browser.
instruction
Render citations as evidence, not decoration
Map annotation offsets to plain answer text, validate URL protocols and file authorization, render citations visibly and clickably, and expose a source drawer with cited and consulted evidence labeled separately.
Why this step matters
OpenAI requires visible clickable inline citations for web-derived information, and users need to know which sources actually support a claim versus which were merely consulted.
What to understand
Render model text with textContent and create link nodes from validated metadata rather than accepting generated HTML.
A file citation points to an application authorization endpoint, never to an unprotected provider object or storage URL.
System changes
- Adds a stable citation and source-ledger presentation contract.
Syntax explained
cited vs consulted- Prevents the complete search trail from being misrepresented as direct support for every sentence.
Claim [1] [2] [1] Official web source — cited [2] approved-policy.pdf — cited, authorized preview 3 additional web URLs — consulted, not cited
Checkpoint: Review the citation interface
Continue whenKeyboard and screen-reader users can identify and open every citation, while unauthorized file previews remain blocked.
Stop whenStop if citation offsets corrupt text, links are hidden, unsafe protocols pass validation, or file access bypasses authorization.
If this step fails
Citation markers point at the wrong words.
Likely causeText was transformed before annotation offsets were applied.
Compare original output_text with rendered textTest Unicode and multiline fixtures
ResolutionApply annotations to the unchanged provider text before presentation-only transformations.
Stop conditions
- Stop if citation offsets corrupt text, links are hidden, unsafe protocols pass validation, or file access bypasses authorization.
config
Enforce identity, quotas, and source policy
Resolve tenant and vector store server-side, rate-limit users, cap concurrent research, validate domains against an allowlist, enforce a cost reservation, and reject requests that exceed the policy before calling OpenAI.
Why this step matters
Provider rate limits protect the project globally; product policy must also prevent one user, tenant, or prompt from consuming the budget or changing data scope.
What to understand
Use a shared rate-limit and concurrency store when multiple instances serve traffic.
Reserve estimated budget before the request and reconcile it with actual usage afterward.
System changes
- Adds application authorization, quota, concurrency, and allowed-domain policy.
Syntax explained
externalWrites: false- Documents that this research session has no consequential action capability.
src/policy.mjsexport const policy = {
maxQuestionChars: 4000,
maxConcurrentPerUser: 1,
maxRequestsPerHour: 12,
maxOutputTokens: 5000,
maxFileResults: 8,
allowedDomains: ["openai.com", "nist.gov", "ietf.org"],
externalWrites: false
};policy=research-v1 user=user_hmac_… tenant=tenant-a store=vs-approved quota=reserved domains=3
Checkpoint: Attempt policy violations
Continue whenUnknown tenants, arbitrary stores, extra domains, oversized questions, and exhausted budgets are rejected before provider work starts.
Stop whenStop if client input can expand domains, stores, tools, output bounds, model, or reasoning effort.
If this step fails
Limits work on one instance but fail under load.
Likely causeCounters are stored in process memory.
Send concurrent requests through two instancesInspect shared-store keys
ResolutionMove reservations and concurrency leases to a shared atomic store before scaling.
Stop conditions
- Stop if client input can expand domains, stores, tools, output bounds, model, or reasoning effort.
config
Build citation and abstention evaluations
Create fixtures with expected sources, forbidden sources, stale facts, conflicting documents, injection text, cross-tenant probes, and unanswerable questions; score retrieval, citation entailment, completeness, and abstention.
Why this step matters
A citation-rich demo can still be wrong, stale, expensive, or unsafe; frozen cases turn quality and evidence expectations into a release decision.
What to understand
Score the cited passage against the claim, not merely the presence of an annotation.
Keep model-graded signals secondary to deterministic source, authorization, and required-phrase checks.
System changes
- Creates a versioned research evaluation dataset and release thresholds.
Syntax explained
citation entailment- Measures whether the cited evidence supports the generated claim.
eval/cases.json[
{
"id": "policy-current-public",
"question": "What changed and what evidence supports it?",
"requiredSourceKinds": ["file", "url"],
"minimumCitations": 2,
"mustMentionUncertainty": true
},
{
"id": "unanswerable",
"question": "State an unsupported private forecast.",
"expected": "abstain"
}
]cases=42 retrieval_recall=0.95 citation_entailment=0.97 abstention=1.00 cross_tenant_leaks=0
Checkpoint: Run the frozen evaluation set
Continue whenAll authorization and injection cases pass, no unsupported answer is promoted, and quality/cost stay within the approved regression band.
Stop whenStop on any cross-tenant retrieval, unsafe tool expansion, fabricated citation, or material entailment regression.
If this step fails
Evaluation scores fluctuate between runs.
Likely causeThe cases, model, corpus, web freshness, or scoring rubric are not pinned.
Record model, policy, corpus revision, response IDs, and timestamps
ResolutionSeparate deterministic gates from freshness-sensitive measurements and use an explicit variance band.
Stop conditions
- Stop on any cross-tenant retrieval, unsafe tool expansion, fabricated citation, or material entailment regression.
config
Add a real provider smoke test
Run one bounded mixed-source question, assert a non-empty answer, multiple citations, complete source metadata, usage, and a stable response identifier without snapshotting private text.
Why this step matters
Local mocks cannot prove model/tool availability, vector-store processing, annotation shape, or the deployed project's provider permissions.
What to understand
Use a dedicated non-sensitive fixture and strict maximum budget.
Record identifiers and counts while excluding the full question, chunks, and answer from ordinary CI logs.
System changes
- Adds one controlled external API test that incurs bounded search and token cost.
Syntax explained
timeout: 180000- Bounds the child process while allowing a multi-source research request to complete.
test/smoke.mjsimport assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
const result = spawnSync(process.execPath, [
"--env-file=.env",
"src/index.mjs",
"What changed in the supported authentication policy and what current public guidance supports the recommendation?"
], { encoding: "utf8", timeout: 180000 });
assert.equal(result.status, 0, result.stderr);
const payload = JSON.parse(result.stdout);
assert.ok(payload.answer.length > 200);
assert.ok(payload.citations.length >= 2);
assert.ok(payload.consultedSources.length >= payload.citations.filter((item) => item.url).length);
assert.ok(payload.usage.total_tokens > 0);
console.log("RESEARCH_SMOKE_OK", payload.responseId, payload.citations.length);RESEARCH_SMOKE_OK resp_research_01 3
Checkpoint: Run the provider smoke test
Continue whenThe test prints RESEARCH_SMOKE_OK with a response ID and at least two citations.
Stop whenStop if the test uses production-private data, logs answer content, exceeds budget, or passes without citations.
If this step fails
The smoke test times out.
Likely causeResearch latency, project limits, network, or the selected model/tool combination changed.
Check provider status and sanitized error classRun one minimal bounded lookup
ResolutionDo not increase timeouts blindly; identify the changed dependency and re-evaluate latency and cost.
Stop conditions
- Stop if the test uses production-private data, logs answer content, exceeds budget, or passes without citations.
instruction
Operate corpus, cost, and failures
Monitor search calls, source counts, response status, latency, usage, refusals, incomplete responses, policy denials, ingestion failures, review dates, deletions, and evaluation regressions without retaining sensitive content by default.
Why this step matters
Research behavior changes when public sources, private documents, models, and tool policies change, so operations must observe evidence quality and lifecycle rather than uptime alone.
What to understand
Alert on sudden zero-citation answers, source-domain drift, retrieval failures, and cost per completed brief.
Keep response IDs available for provider support while applying a documented retention limit to local metadata.
System changes
- Adds privacy-aware metrics, alerts, corpus review jobs, and deletion reconciliation.
Syntax explained
source-domain drift- Detects new or unexpected domains before they become normalized evidence.
research_requests_total{status="completed"}=118
citation_entailment_ratio=0.97
cross_tenant_denials_total=4
corpus_files_due_review=0Checkpoint: Exercise an ingestion and provider failure
Continue whenThe user receives a safe status, operators receive actionable identifiers, and no secret or private chunk appears in logs.
Stop whenStop if operations require raw corpus text in ordinary logs or cannot identify failed deletions and stale files.
If this step fails
Dashboards look healthy while answer quality degrades.
Likely causeOnly HTTP success and latency are monitored.
Compare citation and abstention evaluations by revision
ResolutionPromote evidence-quality and authorization gates to release and operational alerts.
Stop conditions
- Stop if operations require raw corpus text in ordinary logs or cannot identify failed deletions and stale files.
verification
Release through a reversible canary
Canary the evaluated model, policy, corpus revision, and renderer to internal users, inspect citations and cost, then expand gradually with an immediate kill switch for web search or all research.
Why this step matters
A canary limits the effect of source drift, model changes, rendering defects, or unexpected tool cost while preserving evidence for a safe rollback.
What to understand
Version model, prompt, policy, corpus manifest, and renderer together.
Rollback disables new work first but preserves authorized access to existing audit metadata and deletion controls.
System changes
- Publishes one reviewed research revision to a bounded audience before wider availability.
Syntax explained
kill switch- Disables new web/file research without deleting evidence needed for incident response.
npm run check && npm run smokesyntax=passed RESEARCH_SMOKE_OK resp_research_01 3 release_gate=passed
Checkpoint: Approve canary expansion
npm run check && npm run smokeContinue whenQuality, security, latency, and cost stay within thresholds and reviewers can inspect every source.
Stop whenStop on unsupported cited claims, authorization failure, hidden citations, unexpected domains, or budget regression.
If this step fails
The canary must be rolled back.
Likely causeA release gate failed under real traffic or current sources.
Freeze new requestsPreserve revisions and response IDs
ResolutionRestore the previous evaluated bundle, reconcile in-flight work, and rerun affected cases before reopening.
Stop conditions
- Stop on unsupported cited claims, authorization failure, hidden citations, unexpected domains, or budget regression.
Finish line
Verification checklist
npm run smokeOne bounded run returns an answer, at least two visible citation records, consulted-source metadata, usage, and a response ID.npm run test:policyUnknown stores, extra domains, oversized questions, exhausted quotas, and cross-tenant requests fail before an OpenAI call.npm run evalThe frozen suite meets retrieval, entailment, abstention, injection, latency, and cost thresholds with zero authorization leaks.Recovery guidance
Common problems and safe checks
The answer contains facts but no visible citations.
Likely causeThe UI ignored annotations, the message parser selected the wrong content item, or the model answered without using a search tool.
Inspect output item types and annotation countsVerify tools and the citation-rendering contract
ResolutionFail the request closed for citation-required tasks, preserve identifiers, and correct parsing or instructions before retrying.
A citation opens a source that does not support the sentence.
Likely causeThe cited passage is topically related but does not entail the generated claim.
Compare the exact cited range and nearby source passageRun the frozen citation-entailment evaluation
ResolutionLabel the claim unsupported, tighten instructions and evaluation, and do not treat schema-valid annotations as verified facts.
Private content appears for the wrong tenant.
Likely causeThe browser supplied a vector-store ID or the server reused a global store without authorization.
Inspect tenant-to-store mapping without printing contentReview access logs and affected response IDs
ResolutionDisable retrieval, contain the incident, rotate mappings, enforce server-side store resolution, and notify through the incident process.
Research latency or cost grows unexpectedly.
Likely causeSearch context, reasoning effort, output bounds, corpus size, or request concurrency changed.
Compare policy revision, usage, searches, source count, and p50/p95 latencyReplay the frozen evaluation set
ResolutionRestore the last evaluated configuration and change one bounded parameter at a time.
Reference
Frequently asked questions
Are inline citations automatically correct?
No. They identify source metadata and a generated-text range. Your evaluation must still check whether the cited passage supports the exact claim and whether the source is appropriate.
Why return consulted sources as well as citations?
Inline citations show the references selected for the answer. The sources list gives operators a broader audit trail of URLs consulted during web search and helps explain cost and research behavior.
Can the user choose any vector store?
No. The server must resolve a store from authenticated authorization. Accepting a raw client-supplied ID creates a cross-tenant data exposure risk.
Should every question trigger both tools?
Not necessarily. The model may choose tools, but the application still controls which tools exist and their bounds. Evaluation should confirm that private-policy questions use the corpus and freshness-sensitive questions search the web.
Why use store false?
This reference minimizes ordinary response retention, but file and vector-store objects have their own lifecycle. Review current data controls and implement explicit deletion for every retained object.
Recovery
Rollback
Disable new research, restore the previous evaluated model/policy/prompt/renderer bundle, preserve authorized result metadata, and separately reconcile corpus additions or deletions. Rolling back code does not remove uploaded files, vector stores, responses, logs, or exports.
- Activate the research kill switch and allow only authenticated access to existing results, export, and deletion status.
- Record the failing application digest, model, policy revision, corpus manifest, renderer revision, response IDs, source domains, usage, and evaluation failures.
- Restore the previous schema-compatible bundle and rerun policy, citation, injection, and provider smoke tests.
- Remove or quarantine newly added corpus files through the manifest-driven deletion workflow and verify they no longer appear in retrieval.
- Reopen to the canary only after source rendering, authorization, evidence quality, latency, and cost return to the approved band.
Evidence