WikifitaGitHub live67e8de5
outro · co-scientist/co-scientist-pipeline

Co-Scientist Full Pipeline

Complete data flow from goal input to final overview: parsing, generation, reflection, ranking, evolution, meta-review, and termination

Baixar raw

Co-Scientist Full Pipeline

The Co-Scientist pipeline is a durable, bounded-concurrency multi-agent system orchestrated by a Supervisor that manages a SQLite-backed task queue. A researcher provides a natural-language goal; the system autonomously generates hypotheses, reviews them, runs tournaments, evolves top performers, and produces a final research overview.

High-Level Architecture

flowchart TB
    subgraph Entry
        A[Scientist's Goal] --> B[parse_goal]
        B --> C[ResearchPlan]
    end

    subgraph Core Loop
        C --> D[Generation Agent]
        D -->|record_hypothesis| E[hypothesis row]
        E --> F[Reflection Agent]
        F -->|record_review| G[review row]
        G --> H[AddToTournament]
        H --> I[Ranking Agent]
        I -->|tournament_match_complete| J[Elo Update]
    end

    subgraph Idle Refinement
        J --> K{Queue Empty?}
        K -->|No| I
        K -->|Yes| L[decide_next_steps]
        L -->|tournament batch| I
        L -->|evolution needed| M[Evolution Agent]
        L -->|periodic feedback| N[MetaReview Agent]
        M -->|record_hypothesis| E
        N -->|record_system_feedback| O[SystemFeedback]
        O -->|injected into next generation| D
    end

    subgraph Termination
        K -->|StopReason| P[Finalize]
        P --> Q[MetaReviewAgent Final Overview]
        Q --> R[Markdown Research Report]
    end

Phase 1: Goal Parsing

Entry point: Supervisor.run_session() in co_scientist/agents/supervisor.py

  1. A session row is inserted into SQLite with the goal, budget limits, wall-clock deadline, and a frozen config snapshot
  2. The parse_goal prompt is rendered and sent to Sonnet (single call, forced record_research_plan)
  3. The ResearchPlan is extracted and stored:
    • objective -- atomic research question
    • preferences -- what makes a good hypothesis for this goal
    • constraints -- scope/methodology limits
    • idea_attributes -- adjectives for strong candidates
    • domain_hint -- discipline classification
  4. Initial generation tasks are enqueued: n_initial (default 3) tasks with agent="generation", action="CreateInitialHypotheses", each with a unique idempotency key

Phase 2: Generation

Agent: GenerationAgent in co_scientist/agents/generation.py Prompt: generation.literature or generation.debate Model: Opus with 4000 thinking tokens

Tool Loop Execution

Generation uses the tool loop (co_scientist/llm/tool_loop.py) with up to 8 iterations:

  1. The model receives the prompt with access to search tools: web_search, pubmed_search, arxiv_search, europe_pmc_search, web_fetch
  2. It performs literature searches, reads abstracts, and synthesizes understanding
  3. All URLs from tool results are tracked in seen_urls
  4. The model calls record_hypothesis with a structured hypothesis record
  5. The tool loop detects the terminal tool call and returns immediately
  6. Citation URLs are filtered against seen_urls (anti-hallucination)
  7. The hypothesis is persisted with a deterministic ID: sha256(session_id || origin || statement)

Deduplication

Before inserting, the hypothesis is embedded (Voyage-3-large, 1024-dim) and checked against the session's FAISS index. If cosine similarity exceeds dedup_cosine_threshold (default 0.92), the duplicate is rejected and the existing hypothesis ID is returned.

Follow-Up Scheduling

After hypothesis_created, the Supervisor enqueues:

Task(agent="reflection", action="ReviewHypothesis", target_id=hid, kind="full")

Phase 3: Reflection

Agent: ReflectionAgent in co_scientist/agents/reflection.py Prompt: reflection.full (M3); reflection.verification and reflection.observation in later milestones Model: Opus

Tool Loop Execution

Reflection uses the tool loop with up to 8 iterations:

  1. The model receives the hypothesis wrapped in <HYPOTHESIS_TEXT> tags
  2. It searches for supporting/contradicting evidence using available tools
  3. It calls record_review with a structured review including verdict, scores, evidence, and assumptions
  4. Evidence entries are filtered against seen_urls (same anti-hallucination guard)

State Transition

After review, the hypothesis state transitions from draft to reviewed (only if currently in draft state -- never drags back evolved/pinned hypotheses).

Follow-Up Scheduling

After review_completed, the Supervisor enqueues:

Task(agent="ranking", action="AddToTournament", target_id=hid)

Phase 4: Tournament Ranking

Agent: RankingAgent in co_scientist/agents/ranking.py Model: Sonnet (intentionally weaker to avoid echo-judge bias)

AddToTournament

No LLM call. Initializes the hypothesis's Elo to 1200 and sets state to in_tournament.

RunTournamentBatch

The core ranking loop:

  1. Pair selection via three-bucket probabilistic strategy (see co-scientist-elo-tournament)
  2. Mode selection (pairwise vs. debate based on match count and Elo gap)
  3. LLM comparison -- single call for pairwise, multi-turn for debate
  4. Verdict parsing via regex extraction of "better idea: 1|2"
  5. Elo update via update_elo() with deterministic match IDs
  6. Match persistence to tournament_matches and elo_journal tables

Follow-Up Scheduling

After tournament_match_complete, the Supervisor periodically re-clusters the proximity graph (every full_recluster_every_matches matches, default 20).

Phase 5: Evolution

Agent: EvolutionAgent in co_scientist/agents/evolution.py Model: Opus with 6000 thinking tokens

When Evolution Triggers

The Supervisor's _decide_next_steps() method triggers evolution when:

  • The queue is idle (no pending or in-progress tasks)
  • At least min_mature hypotheses (default 20) have matches_played >= 3
  • This is the idle-refinement path, not a reactive trigger

Strategies

StrategySelectionInputOutput
combineMost idea-distant pair in top-KTwo hypotheses + reviewsSynthesized hypothesis
simplifyTop-1 hypothesisOne hypothesis + reviewSimplified hypothesis
out_of_boxTop-5 hypothesesFive hypothesesNovel hypothesis inspired by analogies
feasibilityTop-1 hypothesisOne hypothesisTechnology-refined hypothesis

Dedup and Persistence

Same dedup + FAISS pattern as Generation. Evolution hypotheses carry parent_ids for lineage tracking. They enter the same draft -> reviewed -> in_tournament pipeline.

Phase 6: Meta-Review (Periodic)

Agent: MetaReviewAgent in co_scientist/agents/metareview.py Prompt: metareview.system Model: Sonnet with 8000 thinking tokens

Trigger

Scheduled every ~50 matches (approximated by: match_count >= (feedback_count + 1) * 50).

What It Synthesizes

  • All session reviews (up to 50, truncated to 3000 chars each)
  • Recent tournament debate rationales (up to 50, truncated to 1500 chars each)

Output

record_system_feedback with:

  • common_weaknesses[] -- recurring critique patterns
  • common_strengths[] -- what reviewers consistently praise
  • suggested_focus_areas[] -- directions the system should explore
  • narrative -- 1-2 paragraph synthesis

Feedback Loop

The narrative is stored as a SystemFeedback row and auto-injected into the next Generation and Evolution prompts via _latest_system_feedback(). This creates a closed learning signal:

reviews -> meta-review -> system_feedback -> generation/evolution -> new hypotheses -> reviews -> ...

Phase 7: Final Overview

Agent: MetaReviewAgent (final action) Prompt: metareview.final Model: Opus with 16000 thinking tokens (maximum) No tools: Produces plain markdown

Trigger

Runs once in Supervisor._finalize() after the main loop exits on any StopReason.

Content

The final overview is structured as:

  1. Executive summary -- what the tournament converged on
  2. Main research directions -- per-direction: claim, supporting hypotheses, open questions, first experiment
  3. Convergence and divergence -- which hypotheses overlap, which are orthogonal
  4. Caveats and limitations -- what was not explored, where domain experts might disagree

If MetaReviewAgent fails, a fallback overview is generated from raw hypothesis metadata.


The Supervisor Main Loop

The Supervisor (co_scientist/agents/supervisor.py) is the heart of the system:

flowchart TD
    A[Main Loop Start] --> B{Check External Stop}
    B -->|aborted| C[Wait for Inflight to Drain]
    B -->|paused| D[Sleep 1s, Retry]
    B -->|running| E{should_stop?}
    E -->|BUDGET/WALL_CLOCK/ELO_STABLE| C
    E -->|None| F{Claim Tasks}
    F --> G[Semaphore-Limited Workers]
    G --> H[Run Task via Agent]
    H --> I[Apply Follow-Up Rules]
    I --> J[Complete Task]
    J --> K[Emit Event to Bus]
    K --> L{Update Elo Snapshot?}
    L -->|match threshold crossed| M[Push Snapshot to Tracker]
    L --> N{Queue Empty?}
    M --> N
    N -->|tasks pending| A
    N -->|empty + inflight| O[Wait for First Complete]
    O --> A
    N -->|empty + idle| P{decide_next_steps}
    P -->|enqueued > 0| A
    P -->|enqueued = 0| Q[Return IDLE]
    C --> R[Finalize]

Bounded Concurrency

Concurrency is controlled by asyncio.Semaphore(cfg.run.concurrency) (default 4). Workers claim tasks from the SQLite queue with optimistic locking (lease-based with configurable timeout and max attempts).

Task Queue Schema

The tasks table in co_scientist/storage/schema.sql:

ColumnPurpose
agentWhich agent handles this task
actionSpecific action (e.g., CreateInitialHypotheses, ReviewHypothesis)
target_idRelated entity (hypothesis_id, etc.)
priorityLower = higher priority (100 default, 80 for ranking, 120 for tournament batch)
statuspending -> leased -> in_progress -> done/failed/dead/cancelled
lease_ownerWorker ID holding the lease
lease_expires_atLease TTL (default 300s, 600s for reflection, 1800s for final overview)
idempotency_keyUNIQUE constraint prevents duplicate task enqueueing
attemptsRetry counter, max 3 by default

Lease Management

Tasks are claimed by setting lease_owner and lease_expires_at. If a worker crashes, the Supervisor reclaims expired leases on resume via task_repo.reclaim_expired_leases(). The max_attempts config (default 3) prevents infinite retries.


Token Budget System

Implemented in co_scientist/llm/budgets.py.

Architecture

A single TokenBudget per session, shared across all concurrent agents. Admission is serialized by asyncio.Lock to prevent race conditions.

Per-Agent Shares

AgentShareReasoning
generation20%Multiple hypotheses, each needing search + synthesis
reflection20%Each hypothesis needs thorough review
ranking25%Multiple tournament matches per session
evolution15%Runs less frequently, on mature hypotheses
metareview10%Periodic + final, relatively rare
proximity2%Embedding updates, lightweight
reserve8%Buffer for overages

Admission Flow

  1. admit(agent, est_tokens, est_usd) -- blocks if session budget or agent share would be exceeded
  2. Agent executes the LLM call
  3. settle(agent, est_tokens, est_usd, actual_usd, ...) -- releases reservation and credits actual usage

Cost Estimation

The routing module (co_scientist/llm/routing.py) maintains a comprehensive PRICE_TABLE covering Anthropic, OpenAI, Google, Meta, and Mistral models. Unknown models fall back to family-hint matching (e.g., any model containing "flash" gets flash-tier pricing) or a conservative Sonnet-class default.


Model Routing

The route() function in co_scientist/llm/routing.py maps (agent, mode) pairs to specific model configurations:

AgentModeDefault ModelThinking Tokens
parse_goal--claude-sonnet-4-60
generationliteratureclaude-opus-4-74000
generationdebateclaude-opus-4-78000
reflectionfullclaude-opus-4-70
reflectionverificationclaude-opus-4-712000
reflectionobservationclaude-opus-4-76000
rankingpairwiseclaude-sonnet-4-64000
rankingdebateclaude-sonnet-4-68000
evolutioncombineclaude-opus-4-76000
evolutionout_of_boxclaude-opus-4-76000
evolutionsimplifyclaude-opus-4-70
evolutionfeasibilityclaude-opus-4-70
metareviewsystemclaude-sonnet-4-68000
metareviewfinalclaude-opus-4-716000
classifier--claude-haiku-4-5-202510010
judge--claude-sonnet-4-60

Degradation Chain

When a model is unavailable, the system walks a soft fallback chain:

claude-opus-4-7 -> claude-sonnet-4-6 -> claude-haiku-4-5-20251001

Certain modes are never-degraded: reflection.verification and metareview.final -- these require maximum capability.

Thinking Budgets

Thinking tokens are only allocated for Opus-class models. Non-Opus models always get thinking_tokens=0. The thinking budget for each mode is configurable in ThinkingCfg.


Event Bus

The EventBus in co_scientist/orchestrator/events.py provides in-process pub/sub for the web UI:

  • Agents publish events via bus.publish(session_id, event_name, payload)
  • SSE handlers subscribe via bus.subscribe(session_id) for async iteration
  • Buffer limit: 256 events per subscriber; oldest events are dropped for slow subscribers
  • The bus is in-process only; on restart, the UI snapshots from the events table

Event Types

EventSourcePayload
session_startedSupervisorgoal, n_initial, budget_usd
task_startedSupervisortask_id, agent, action, target
task_completedSupervisortask_id, kind, follow_hypothesis_ids
task_failedSupervisortask_id, err
match_completeRankingAgentmode, hyp_a, hyp_b, winner, elo_applied
session_doneSupervisorstop_reason

Database Schema

The full SQLite schema in co_scientist/storage/schema.sql (WAL mode, foreign keys enabled):

TablePurposeKey Relationships
sessionsSession config, budget, status, final_overviewParent of all other tables
hypothesesHypothesis records with state machineFK to sessions
reviewsReview records with verdicts and scoresFK to hypotheses + sessions
tournament_matchesHead-to-head comparison resultsFK to hypotheses + sessions
elo_journalAppend-only Elo update ledgerUNIQUE on match_id
tasksDurable task queue with lease managementFK to sessions
transcriptsLLM call logs with token counts and costsFK to sessions + tasks
system_feedbackMeta-review narratives + human preferencesFK to sessions
embeddings_metaFAISS vector index metadataFK to hypotheses
spansOpenTelemetry-style observability spansFK to sessions + tasks
eventsEvent log for UI replayFK to sessions
schema_migrationsLinear migration trackingStandalone

Migrations

Migrations are in co_scientist/storage/migrations/. The system uses a schema_migrations table to track applied versions. Migration v1 uses the canonical schema.sql; subsequent migrations use individual files. Duplicate-column errors during fresh init are gracefully handled (ALTER TABLE becomes a no-op).


Complete Data Flow Summary

sequenceDiagram
    participant S as Scientist
    participant Sup as Supervisor
    participant Gen as Generation
    participant Ref as Reflection
    participant Rank as Ranking
    participant Evo as Evolution
    participant MR as MetaReview
    participant DB as SQLite

    S->>Sup: goal + preferences
    Sup->>DB: INSERT session
    Sup->>DB: parse_goal -> ResearchPlan
    loop n_initial times
        Sup->>DB: enqueue CreateInitialHypotheses
    end

    loop Main Loop
        Sup->>DB: claim task
        alt Generation task
            Sup->>Gen: execute(task)
            Gen->>Gen: tool loop (search -> record_hypothesis)
            Gen->>DB: INSERT hypothesis (state=draft)
            Gen->>Sup: hypothesis_created
            Sup->>DB: enqueue ReviewHypothesis
        else Reflection task
            Sup->>Ref: execute(task)
            Ref->>Ref: tool loop (search -> record_review)
            Ref->>DB: INSERT review
            Ref->>DB: UPDATE hypothesis state -> reviewed
            Ref->>Sup: review_completed
            Sup->>DB: enqueue AddToTournament
        else Ranking task
            Sup->>Rank: execute(task)
            alt AddToTournament
                Rank->>DB: UPDATE hypothesis state -> in_tournament
            else RunTournamentBatch
                Rank->>Rank: select pair, run debate/pairwise
                Rank->>DB: INSERT match + elo_journal
                Rank->>DB: UPDATE hypothesis elos
            end
            Rank->>Sup: tournament_match_complete
        else Evolution task
            Sup->>Evo: execute(task)
            Evo->>Evo: tool loop (combine/simplify/out_of_box)
            Evo->>DB: INSERT hypothesis (state=draft)
            Evo->>Sup: hypothesis_created
            Sup->>DB: enqueue ReviewHypothesis
        else MetaReview task
            Sup->>MR: execute(task)
            alt System Feedback
                MR->>DB: INSERT system_feedback
                Note right of DB: Injected into next Gen/Evo prompts
            else Final Overview
                MR->>MR: synthesize top hypotheses
                MR->>DB: UPDATE session.final_overview
            end
        end
        Sup->>DB: check termination
    end

    Sup->>MR: GenerateFinalResearchOverview
    MR->>DB: UPDATE session.status -> done
    Sup->>S: session_id

Default Configuration

Key defaults from co_scientist/config.py:

ParameterValuePurpose
run.concurrency4Max parallel agent workers
run.max_ideas60Cap on total hypotheses
run.wall_clock_seconds7200 (2h)Session time limit
run.budget_usd$25.00Session USD cap
ranking.elo_initial1200Starting Elo for new hypotheses
ranking.k_factor_new32Fast convergence for new hypotheses
ranking.k_factor_warm16Stable Elo for experienced hypotheses
termination.elo_stability_k5Top-K to monitor for convergence
termination.elo_stability_n3Snapshots needed for stability
termination.elo_stability_eps25.0Max Elo drift within stable window
evolution.min_mature20Min hypotheses with >= 3 matches before evolution
evolution.top_k5Top hypotheses to evolve
vectors.dedup_cosine_threshold0.92Cosine similarity threshold for dedup
lease.default_seconds300Task lease TTL

Cross-references