OneLinersCommand workbench
Guides
AI/ML / Software Engineering / Security

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.

140 min10 stepsChanges system stateRevision 1
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 10 steps completed
Goal

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.

Supported environments
  • Node.js 22.22.2
  • OpenAI Node SDK 7.1.0
  • OpenAI Responses API 2026-07-29
  • Research model gpt-5.5
Prerequisites
  • 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.
Operating boundary

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

System
  • 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.
Observable outcome
  • 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.

Corpus manifestTracks file owner, classification, checksum, vector-store file ID, review date, and deletion state.
Research APIValidates the question, identity, allowed domains, budget, output limit, and tool configuration before calling Responses.
OpenAI toolsRetrieve current web sources and relevant private chunks while returning typed search calls, results, annotations, and usage.
Citation rendererMaps validated annotation offsets to visible, clickable URL or file references without rendering arbitrary model HTML.
Evaluation and auditMeasures retrieval relevance, citation entailment, answer completeness, refusal, latency, cost, and corpus lifecycle.
  1. 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.
  2. An authenticated user submits a bounded question; the application resolves the correct vector store and allowed-domain policy server-side.
  3. Responses runs file and web searches, returns an answer message, inline annotations, optional included retrieval results, the complete consulted-source list, and usage.
  4. The application rejects missing output, stores only policy-approved metadata, and returns a normalized answer and source ledger to the UI.
  5. 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.
  6. 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.5

Security 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.
01

decision

Freeze the research and evidence contract

read-only

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.
Example output / evidence
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.

Safe checks
  • 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.
02

config

Create the pinned research project

caution

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.
File package.json
Configuration
{
  "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"
  }
}
Example output / evidence
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.

Safe checks
  • node --version
  • npm 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.
03

command

Create the vector store and ingest reviewed files

caution

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.
Command
node --env-file=.env scripts/ingest.mjs corpus/approved-policy.pdf
Example output / evidence
file=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.pdf

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

Safe checks
  • Inspect file status and sanitized error
  • Validate 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.
04

config

Implement bounded web and file research

caution

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.
File src/index.mjs
Configuration
import 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));
Example output / evidence
{
  "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.

Safe checks
  • Inspect response.status and output item types
  • Preserve 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.
05

instruction

Render citations as evidence, not decoration

read-only

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.
Example output / evidence
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.

Safe checks
  • Compare original output_text with rendered text
  • Test 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.
06

config

Enforce identity, quotas, and source policy

caution

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.
File src/policy.mjs
Configuration
export const policy = {
  maxQuestionChars: 4000,
  maxConcurrentPerUser: 1,
  maxRequestsPerHour: 12,
  maxOutputTokens: 5000,
  maxFileResults: 8,
  allowedDomains: ["openai.com", "nist.gov", "ietf.org"],
  externalWrites: false
};
Example output / evidence
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.

Safe checks
  • Send concurrent requests through two instances
  • Inspect 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.
07

config

Build citation and abstention evaluations

read-only

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.
File eval/cases.json
Configuration
[
  {
    "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"
  }
]
Example output / evidence
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.

Safe checks
  • 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.
08

config

Add a real provider smoke test

caution

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.
File test/smoke.mjs
Configuration
import 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);
Example output / evidence
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.

Safe checks
  • Check provider status and sanitized error class
  • Run 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.
09

instruction

Operate corpus, cost, and failures

read-only

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.
Example output / evidence
research_requests_total{status="completed"}=118
citation_entailment_ratio=0.97
cross_tenant_denials_total=4
corpus_files_due_review=0

Checkpoint: 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.

Safe checks
  • 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.
10

verification

Release through a reversible canary

caution

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.
Command
npm run check && npm run smoke
Example output / evidence
syntax=passed
RESEARCH_SMOKE_OK resp_research_01 3
release_gate=passed

Checkpoint: Approve canary expansion

npm run check && npm run smoke

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

Safe checks
  • Freeze new requests
  • Preserve 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

Mixed-source researchnpm run smokeOne bounded run returns an answer, at least two visible citation records, consulted-source metadata, usage, and a response ID.
Authorization and limitsnpm run test:policyUnknown stores, extra domains, oversized questions, exhausted quotas, and cross-tenant requests fail before an OpenAI call.
Citation evaluationnpm 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.

Safe checks
  • Inspect output item types and annotation counts
  • Verify 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.

Safe checks
  • Compare the exact cited range and nearby source passage
  • Run 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.

Safe checks
  • Inspect tenant-to-store mapping without printing content
  • Review 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.

Safe checks
  • Compare policy revision, usage, searches, source count, and p50/p95 latency
  • Replay the frozen evaluation set

ResolutionRestore the last evaluated configuration and change one bounded parameter at a time.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Use only file_search for a controlled internal policy assistant where current public information is neither required nor allowed.
  • Use only web_search for a public-current-events researcher with no private corpus, while keeping domain and cost policy explicit.
  • Use a custom retrieval pipeline when chunking, ranking, regional storage, deletion evidence, or access-control requirements cannot be met by the managed vector-store workflow.

Operate it safely

  • Add an authenticated web interface that renders annotation ranges accessibly, opens external links safely, and gives private file citations an authorized preview endpoint.
  • Create a corpus lifecycle job for checksum-based revisions, processing failures, review dates, deletion, and proof that removed material is no longer retrieved.
  • Build evaluation dashboards for citation precision, entailment, source diversity, abstention, freshness, latency, token usage, tool calls, and per-user cost.
  • Introduce a human-reviewed export format for research briefs without adding write tools to the model session.

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.

  1. Activate the research kill switch and allow only authenticated access to existing results, export, and deletion status.
  2. Record the failing application digest, model, policy revision, corpus manifest, renderer revision, response IDs, source domains, usage, and evaluation failures.
  3. Restore the previous schema-compatible bundle and rerun policy, citation, injection, and provider smoke tests.
  4. Remove or quarantine newly added corpus files through the manifest-driven deletion workflow and verify they no longer appear in retrieval.
  5. Reopen to the canary only after source rendering, authorization, evidence quality, latency, and cost return to the approved band.

Evidence

Sources and review

Verified 2026-07-29Review due 2026-10-27
Web search | OpenAI APIofficialFile search | OpenAI APIofficialRetrieval | OpenAI APIofficialCreate a model response | OpenAI API referenceofficialProduction best practices | OpenAI APIofficialError codes | OpenAI APIofficialYour data | OpenAI APIofficial