Skip to content

Repository files navigation

swift-research-agent

English | 日本語

Stop a research agent citing pages it never opened — its answer is checked against a ledger of what it actually fetched, and sent back when it does not hold up.

Swift Platforms License

Overview

An agent that searches the web will happily produce a citation from a search snippet, or from memory, or from nothing at all. This package gives it web_search and fetch tools that record every source they touch in a ledger, and then checks the finished answer against that ledger before anyone sees it.

An answer that cites nothing at all is rejected outright — only a tool result can supply a URL, so requiring one indirectly requires the agent to go and look. Beyond that, each cited URL has to be present in the ledger and to have been fetched successfully; a search result the agent only glanced at is not enough. Matching is on a normalised key, so www., tracking parameters, fragments and trailing slashes all fold together, while a different path or query is a different page. The check runs on recorded state alone: no network call, no second model, same verdict every time.

When the answer fails, the agent is told which citations were bad and asked to try again, up to a retry limit you set. When it passes, the sources travel with the answer as structured metadata, so the surface showing it can list references without re-deriving them.

Every attempt is checked, the last one included, so maxRetries: 0 means one attempt that is still checked. An answer that never passes is never completed: once the retry budget is spent the task fails, carrying the violations and the rejected text, so nothing downstream can mistake it for a verified answer.

One limit, before you call this hallucination-proof. Only provenance is checked, never support — a page that was fetched can be cited for a claim it never made, or contradicts. What it does rule out is a citation to a URL this task never fetched: one recalled from training, one invented, or one seen in a snippet and never opened.

  • Search backends are swappable — Serper and Brave included, or chain several so one outage does not end the task
  • Bad days degrade instead of failing — request rate limiting, a circuit breaker that stops hammering a failing provider, and a bounded result cache
  • The tool set is decided once — the same configuration drives the tools, the system prompt and the agent's self-description, so they cannot drift apart
  • Fetching can be fenced — restrict to an allow-list of domains and cap response size

Quick Start

import ResearchStore
import ResearchAgentTools

// One session-scoped ledger, shared by the tools and the gate
let registry = SourceRegistry()

let toolKit = ResearchToolKit.serper(
    registry: registry,
    apiKey: "YOUR_SERPER_API_KEY",
    gl: "jp",
    hl: "ja"
)

print(toolKit.availableToolIDs)  // [.webSearch, .fetch]

Check an answer yourself, without running a whole agent:

import ResearchAgent

await registry.registerFetch(url: "https://example.com/article", title: "Example", content: "...")

let issues = await ResearchCitationGate.validate(
    text: "See https://example.com/article for details.",
    registry: registry
)
if !issues.isEmpty {
    let corrective = ResearchCitationGate.corrective(issues: issues)  // feed back to the model
}

Documentation

ResearchAgent — assembling the agent, the citation gate and the retry loop, including Getting Started.

ResearchAgentTools — the tools, the search providers, and what happens when one fails.

ResearchStore — the source ledger the gate reads.

Installation

// Package.swift
dependencies: [
    .package(url: "https://github.com/no-problem-dev/swift-research-agent.git", .upToNextMinor(from: "0.3.0"))
]
.product(name: "ResearchAgent",      package: "swift-research-agent"),
.product(name: "ResearchAgentTools", package: "swift-research-agent"),
.product(name: "ResearchStore",      package: "swift-research-agent"),

Requirements

  • iOS 17.0+ / macOS 14.0+ / Linux
  • Swift 6.2+

License

MIT — see LICENSE.

About

Stop a research agent citing pages it never opened — its answer is checked against a ledger of what it actually fetched, and sent back when it does not hold up.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages