Skip to content
Define the acceptance contract
Public Preview

Requesting Web research: contract and source review

This how-to explains how to define an acceptance contract and request source-linked Web research via the Python SDK, then review returned sources.

This page covers defining acceptance contracts, requesting source-linked fields, reviewing sources, and recovering safely from Web research Task results.

  • Acceptance contract definition for public research questions.
  • Source-linked field requests and response model validation.
  • Source review and acceptance test application.
  • Safe recovery from SDK errors and evidence gaps.

Summaries were generated by AI.

Use the Python SDK to ask for dated Web research and a result that retains source URLs, disagreements, and evidence gaps. A Task request does not guarantee that Web research runs or that it returns a supported claim. The example stops if it receives none; review returned sources before your application accepts a claim.

Define the acceptance contract

Before you submit the Task request, define:

  • the public question and the date at which the answer must be valid;
  • the material claims that need support and the preferred primary source types;
  • how the result must report conflicts, missing dates, and evidence gaps;
  • the claims that need a person or an independent rule-based check.

Keep the research request public. Do not include a credential, private URL, confidential passage, or unnecessary personal data.

Request source-linked fields

This example asks a public question about an official Python release. Replace the question and review criteria for your own workflow.

import asyncio
from datetime import UTC, datetime, timedelta
from pydantic import BaseModel, Field

from dualeai import ask, create_sdk


class Evidence(BaseModel):
    final_url: str
    publisher: str
    published_at: str | None = None
    excerpt: str


class Claim(BaseModel):
    text: str
    sources: list[Evidence] = Field(min_length=1)


class WebResearchResult(BaseModel):
    answer: str
    claims: list[Claim] = Field(default_factory=list)
    disagreements: list[str] = Field(default_factory=list)
    evidence_gaps: list[str] = Field(default_factory=list)
    valid_as_of: str


async def main() -> None:
    as_of = datetime.now(UTC).date().isoformat()
    async with create_sdk() as sdk:
        response = await ask(
            action=(
                f"Research the published release date of Python 3.10.0 as of {as_of}. "
                "Prefer official Python.org sources. "
                "For each material claim, return the final URL, publisher, publication date, "
                "and a short supporting excerpt from every source you use. Report disagreements "
                "and evidence gaps. Return no claim when the available pages do not support it."
            ),
            res=WebResearchResult,
            deadline=datetime.now(UTC) + timedelta(minutes=10),
            sdk=sdk,
        )
        print(response.task_id)
        result = await response.model()

        if not result.claims:
            print("STOP: no supported claims")
            return

        print(
            "SOURCE_REVIEW_REQUIRED",
            len(result.claims),
            len(result.evidence_gaps),
        )
        for claim in result.claims:
            print(f"CLAIM: {claim.text}")
            for source in claim.sources:
                print(f"SOURCE: {source.final_url}")


asyncio.run(main())

When the result contains at least one source-linked claim, the example prints its claim text and URLs for review:

<task_id>
SOURCE_REVIEW_REQUIRED <claim_count> <gap_count>
CLAIM: <claim_text>
SOURCE: <final_url>

Choose a deadline that fits your workflow. The ten-minute deadline above is an example, not a web completion guarantee.

The response model gives the final Task Result a fixed shape and requires source material for each returned claim. It validates structure, not source independence or factuality.

Review the sources

SOURCE_REVIEW_REQUIRED is not an approval signal. Open the material sources and apply the full acceptance test in Sources and factuality. If a source fails, narrow the claim, request another public source, or keep an evidence gap.

Recover safely

If response.model() raises an SDK or validation error, record response.task_id and read Errors and reliability before you submit another Task request. A submission with a new identifier creates new work.

If the result contains no supported claim, keep the gap. Change one search condition at a time or use another public source.