Commit graph

17 commits

Author SHA1 Message Date
Austin Schaefer
53b4f572df Merge master into worktree-deep-research-max-turns-report
Some checks failed
CI / test (pull_request) Failing after 54s
2026-08-19 15:03:24 +02:00
Austin Schaefer
cd580f3bec chore: Update rig to 0.42 2026-08-19 12:11:47 +02:00
Austin Schaefer
8f4af514a3 Merge master (rebrand to doubleo7) into this branch
All checks were successful
CI / test (pull_request) Successful in 3m38s
Resolves the Cargo.lock conflict by regenerating it, and picks up
master's rename (deep_research -> doubleo7 crate/binary name, Cli ->
Doubleo7 struct) cleanly through everything this branch added
(--doc/documents.rs/retrieval.rs). Also renamed a leftover
"deep_research-test-" temp-dir prefix in documents.rs's tests for
consistency with the rebrand.
2026-08-18 16:19:39 +02:00
Austin Schaefer
ff9f9455a6 Chunk uploaded documents instead of truncating them at 20K chars
All checks were successful
CI / test (pull_request) Successful in 11m5s
A flat 20K-char cutoff (copied from the fetched-web-page limit) silently
dropped everything past the first ~20KB of a larger file, and even
within the cutoff, embedding a whole multi-page document as one vector
made retrieval coarse — the vector just averages out whatever topics
the document covers.

Split each file into ~1500-char chunks via text-splitter (recursive
semantic-boundary splitting: paragraph > sentence > word, never mid-word)
and embed each chunk as its own document, tagged with its source and
part number. This removes the practical size ceiling — a large file
chunks the same way a short one does — and sharpens retrieval by letting
it surface the specific passage relevant to a query. It also incidentally
caps the worst-case retrieval payload: 5 chunks now tops out around
7500 chars versus the old worst case of 5 full 20K-char documents.

Verified against a live Ollama nomic-embed-text pull: a short document
still embeds as a single chunk, unchanged from before.
2026-08-18 14:43:14 +02:00
Austin Schaefer
5bb4ed165d chore: rebrand project
All checks were successful
CI / test (pull_request) Successful in 3m11s
2026-08-18 14:26:50 +02:00
Austin Schaefer
f2c10783db Extract swear_cleanup to its own repo, flatten deep_research to root
Some checks failed
CI / test (push) Failing after 6s
CI / test (pull_request) Failing after 7s
deep_research is the only project this repo is meant to showcase, so the
Cargo workspace wrapping it and an unrelated side project no longer earns
its keep:

- swear_cleanup moved to a new standalone local repo (~/dev/swear_cleanup,
  not pushed anywhere) via `git subtree split`, with its pre-workspace-
  split history (when it lived at src/swear_cleanup/ in a single shared
  crate) spliced onto its post-split history rather than starting from a
  single flattened snapshot. FINDINGS.md, which was sitting at this repo's
  root but was actually swear_cleanup's own build log, went with it.
- deep_research/{src,Cargo.toml,README.md,docs} moved to the repo root;
  the [workspace] table collapsed into a plain [package] manifest with
  dependency versions inlined from the old [workspace.dependencies].
- Cargo.toml keeps an explicit empty [workspace] table (not just omitted)
  so that checking this repo out as a nested git worktree — this
  project's own normal workflow — can't accidentally inherit a stale
  ancestor directory's workspace manifest, which is exactly what broke
  the build while testing this change from a worktree.
- .forgejo/workflows/deep_research-ci.yml -> ci.yml, dropping the now-
  meaningless -p deep_research scoping and path filters (redundant when
  it's the only thing in the repo).
- README.md and docs/case-study.md updated for the flattened commands
  (cargo run/test with no -p flag); their relative links to each other
  and to src/ were already correct since both moved together.

Verified: cargo build/test/clippy/fmt all clean from the new repo root.
2026-08-18 13:43:26 +02:00
Austin Schaefer
21030462b1 Prototype an agentic summarizer for max-turns recovery
Add summarize_partial_history: a one-shot writer-model pass that turns an
annotated transcript (tool calls with their args, so a fetch's URL or a
search's query stays attached to its result, plus results and interim
notes) into a proper footnote-style findings dump, instead of the flat
concatenation partial_findings_from_history produces on its own.

It's wired in as the MaxTurnsError recovery path in gather_findings, but
partial_findings_from_history stays as the fallback for an empty transcript
or if the summarizer call itself fails — the one guaranteed recovery path
shouldn't have a second turn-budget/model failure as a single point of
failure.

Observability: instrumented with the same #[tracing::instrument(fields(
gen_ai.agent.name = ...))] + spinner pattern as the researcher/reviewer/
writer phases, with info!/warn! events on success, empty-transcript
skip, and summarizer failure.

Also: cargo fmt across the crate (unrelated formatting drift had
accumulated), and adds unit tests for the new transcript_lines /
annotated_transcript_from_history helpers.
2026-08-18 11:54:23 +02:00
Austin Schaefer
55f4f7eeb3 feat: stream the report to the terminal as the writer generates it
Wires up starter.rs -> core.rs (CLI parsing and observability init moved
into core, main.rs left as a thin entry point) and switches the report
phase from Agent::prompt to rig's stream_prompt, printing each text
delta to stdout as it arrives instead of waiting for the full response.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 12:17:26 +02:00
Austin Schaefer
0bb5870f66 refactor: split into a Cargo workspace with per-project dependency sets
deep_research and swear_cleanup were sharing one Cargo.toml, so every
build compiled clap/indicatif/scraper/chrono (only needed by
deep_research) even when just building swear_cleanup for its own
course work, and vice versa. Moves each into its own workspace member
crate (deep_research/, swear_cleanup/) with an independent Cargo.toml
declaring only the deps it actually uses; common deps/versions are
pinned once via [workspace.dependencies] so the two don't drift.

Verified `cargo build -p swear_cleanup` alone no longer pulls in
clap/indicatif/scraper/chrono (schemars still compiles for it, but
that's a direct transitive dependency of rig itself, not something
this split can avoid). Also verified the relocated deep_research
binary still runs end-to-end against live Ollama with correct
footnote citations and sources.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 19:43:13 +02:00
Austin Schaefer
3499e0ac6b feat: formalize deep research tool as a clap CLI with gated logging and a progress spinner
Adds a clap-derive Cli (topic argument, --log-level flag) so the
research loop is a proper command-line tool instead of a raw
env::args().nth(1) read. Logging is now opt-in: tracing only
initializes a subscriber when --log-level is passed, so the terminal
stays clean by default. When logging is off, each research phase
(researcher/reviewer/writer) shows an indicatif spinner instead, so
the user isn't staring at a blank terminal during the 1-3 minute
Gemma tool-calling turns.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 19:32:10 +02:00
Austin Schaefer
34b93eae3d feat: add current-date context and footnote-style citations to research loop
Interpolates today's date into the researcher's preamble so it can judge
source freshness instead of relying on training-cutoff knowledge, and
asks it to cite facts with bracketed footnote numbers backed by a
Sources list, which the writer agent is now instructed to preserve
through to the final report.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 19:06:15 +02:00
Austin Schaefer
3fd18e6a7c feat: add a reviewer agent that gates and redirects the research loop
Adds a reviewer step (gemma4-e4b, fresh context) between gathering and
writing: it uses rig's typed Extractor to judge whether the findings'
conclusions actually follow from their cited sources, rather than
relying on free-text parsing. research() is now a plain bounded loop —
"the least agentic design that solves the problem", per rig's own
workflow guidance — that reruns the researcher with the reviewer's
solid_findings/gaps feedback folded into the next round's task until
it approves or MAX_RESEARCH_ROUNDS runs out.
2026-08-14 12:58:39 +02:00
Austin Schaefer
9212914282 feat: deep research agentic loop with rig AgentRunner + Gemma models
Pins rig to the newest published crates.io release (0.41.0) instead of
the git main branch, and adapts swear_cleanup's revise.rs to that
release's API (OneOrMany::first() returns T directly, raw_completion
folded into CompletionResponse::raw_response).

The research agent (gemma4:26b) drives rig's AgentRunner tool-calling
loop with two lean #[rig::tool_macro] tools — a DuckDuckGo HTML search
and a page-text fetcher — to gather and cross-check findings. A second
agent (gemma4-e4b) turns those findings into a structured report; the
smaller/faster model suffices there since it's reformatting already-
digested notes rather than doing multi-step research reasoning.
2026-08-14 12:40:09 +02:00
Austin Schaefer
57ca9555b4 feat: structured tracing observability
Enable Rig's built-in tracing spans (model, token usage, cache hits,
latency) via tracing-subscriber, filterable through RUST_LOG and
defaulting to info level. Logs write to stderr so stdout stays
reserved for program output. Standardizes the remaining ad-hoc
println! diagnostics (server startup, per-iteration revision progress,
non-convergence) into structured tracing events at appropriate levels.
2026-08-05 15:23:30 +02:00
Austin Schaefer
62a92a88bd feat: auto-start llama-server, extract server module
Checks whether llama-server is already healthy on startup and spawns it
from configured binary/model paths if not, polling until ready. Server
infra config (binary, model path, host, port, context size) split out
of prompts.toml into its own server.toml, and all of it lives in a new
server module rather than inline in main.rs, alongside a single reused
HTTP client and a shared health-check helper. Gemma client setup now
runs concurrently with the server health-check/spawn since they're
independent.
2026-08-05 14:45:44 +02:00
Austin Schaefer
507b25d370 feat: Introduce two agent flow with profanity verification. 2026-08-05 14:21:38 +02:00
Austin Schaefer
9bad1dfc2d cargo new scaffold 2026-07-31 10:20:46 +02:00