Skip to content

Agents#

The specialist roles the strategizer delegates to.

adda.StrategizerAgent #

Default orchestrator agent for f3dasm agentic runs.

Source code in src/adda/_src/agents/strategizer.py
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
class StrategizerAgent(Agent):
    """Default orchestrator agent for f3dasm agentic runs."""

    system_prompt = STRATEGIZER_SYSTEM_PROMPT
    # Single source of truth for this agent's tools. Topology tools
    # (Delegate/Wait/RecallHistory) are auto-granted to any node
    # with outgoing edges and need not be declared. Everything else — including
    # the hypothesis/milestone/store tools that used to be force-injected — is
    # declared here.
    def build_closure_tools(
        self,
        study_dir,
        delegation_id=None,
        lit_reviewer_notes_dir=None,
    ) -> dict:
        """Base corpus tools, plus the on-demand f3dasm API lookup.

        The strategizer chooses samplers and optimizers without writing them,
        so it needs to know what f3dasm provides natively -- and without a
        lookup it guesses (CMA-ES and a GP were both once claimed as built in).
        """
        tools = super().build_closure_tools(
            study_dir,
            delegation_id=delegation_id,
            lit_reviewer_notes_dir=lit_reviewer_notes_dir,
        ) or {}
        from ..knowledge.f3dasm_api import build_f3dasm_api_closures
        tools.update(build_f3dasm_api_closures())
        return tools

    tools = frozenset({"Done", "WriteNote", "ReadNote",
                       "WriteDeliverable", "WriteCell", "ShowNotebook",
                       "RunNotebook", "RunScratch", "Wait",
                       # hypothesis ledger — full read+mutate
                       "HypothesisPropose", "HypothesisUpdate",
                       "HypothesisList",
                       # process milestones
                       "MilestoneList", "MilestoneSet",
                       # canonical store read
                       "QueryStore", "OracleStatus",
                       "ReadProblemStatement"})
    # NOTE (audit): CancelDelegation is opt-in (plug-and-play). The status poll
    # that used to be GetStatus is Wait(block=False). CancelDelegation is
    # intentionally NOT listed —
    # dropped from production (drop-but-don't-delete); its def + opt-in gate
    # remain, so restoring it is one line: add "CancelDelegation" above.
    reset_on_checkpoint = False
    role = "strategizer"
    description = (
        "Orchestrates the run: forms hypotheses, plans delegations, "
        "synthesises evidence into a final conclusion. Entry node."
    )
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
report_sections: tuple[str, ...] = ('### Actions taken', '### Conclusions', '### Numbers') class-attribute instance-attribute #
system_prompt = STRATEGIZER_SYSTEM_PROMPT class-attribute instance-attribute #
tools = frozenset({'Done', 'WriteNote', 'ReadNote', 'WriteDeliverable', 'WriteCell', 'ShowNotebook', 'RunNotebook', 'RunScratch', 'Wait', 'HypothesisPropose', 'HypothesisUpdate', 'HypothesisList', 'MilestoneList', 'MilestoneSet', 'QueryStore', 'OracleStatus', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = False class-attribute instance-attribute #
role = 'strategizer' class-attribute instance-attribute #
description = 'Orchestrates the run: forms hypotheses, plans delegations, synthesises evidence into a final conclusion. Entry node.' class-attribute instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir, delegation_id=None, lit_reviewer_notes_dir=None) -> dict #

Base corpus tools, plus the on-demand f3dasm API lookup.

The strategizer chooses samplers and optimizers without writing them, so it needs to know what f3dasm provides natively -- and without a lookup it guesses (CMA-ES and a GP were both once claimed as built in).

Source code in src/adda/_src/agents/strategizer.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
def build_closure_tools(
    self,
    study_dir,
    delegation_id=None,
    lit_reviewer_notes_dir=None,
) -> dict:
    """Base corpus tools, plus the on-demand f3dasm API lookup.

    The strategizer chooses samplers and optimizers without writing them,
    so it needs to know what f3dasm provides natively -- and without a
    lookup it guesses (CMA-ES and a GP were both once claimed as built in).
    """
    tools = super().build_closure_tools(
        study_dir,
        delegation_id=delegation_id,
        lit_reviewer_notes_dir=lit_reviewer_notes_dir,
    ) or {}
    from ..knowledge.f3dasm_api import build_f3dasm_api_closures
    tools.update(build_f3dasm_api_closures())
    return tools

adda.ImplementerAgent = F3dasmImplementerAgent module-attribute #

adda.DataGeneratorAgent #

The universal oracle standardizer.

Conforms ANY evaluation source — a compiled binary, an external solver (FEM/CFD/Julia), a dataset with a quirky convention, raw physics, or a plain-language spec — into one validated f3dasm DataGenerator, and writes a registration manifest so the runtime can register it as the canonical oracle (reached by the implementer through get_evaluator()).

Validates the interface on exactly one sample and the model against expectations that come from outside the code (feature model_verification); does NOT run large-scale experiments, choose samplers, or optimize. Consults the literature reviewer for methodology on novel physics before implementing.

Source code in src/adda/_src/agents/datagenerator.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
class DataGeneratorAgent(Agent):
    """The universal oracle standardizer.

    Conforms ANY evaluation source — a compiled binary, an external solver
    (FEM/CFD/Julia), a dataset with a quirky convention, raw physics,
    or a plain-language spec — into one validated f3dasm DataGenerator, and
    writes a registration manifest so the runtime can register it as the
    canonical oracle (reached by the implementer through get_evaluator()).

    Validates the interface on exactly one sample and the model against
    expectations that come from outside the code (feature
    ``model_verification``); does NOT run large-scale experiments,
    choose samplers, or optimize. Consults the literature reviewer for
    methodology on novel physics before implementing.
    """

    def build_closure_tools(
        self,
        study_dir,
        delegation_id=None,
        lit_reviewer_notes_dir=None,
    ) -> dict:
        """Base corpus tools, plus the on-demand f3dasm API lookup.

        Only the two agents that WRITE f3dasm carry this tool. Every tool costs
        catalog tokens in every model call for the agent holding it, so a
        lookup the critic and strategizer never need does not go to them.

        super() is called, so the literature-corpus tools survive: this agent
        wants papers for methodology AND the API for mechanics.
        """
        tools = super().build_closure_tools(
            study_dir,
            delegation_id=delegation_id,
            lit_reviewer_notes_dir=lit_reviewer_notes_dir,
        ) or {}
        from ..knowledge.f3dasm_api import build_f3dasm_api_closures
        tools.update(build_f3dasm_api_closures())
        return tools


    system_prompt = DATA_GENERATOR_SYSTEM_PROMPT
    tools = frozenset({
        "Bash", "Edit", "Read", "Write", "Glob", "Grep", "ReportEvals",
        # read-only ledger/store access (single source of truth for tools)
        "QueryStore", "OracleStatus",
        "HypothesisList",
        # manage a backgrounded long job (e.g. Abaqus): poll it / stop it
        "BashOutput", "KillShell",
        "ReadProblemStatement",
    })
    reset_on_checkpoint = True
    role = "datagenerator"
    description = (
        "The universal oracle standardizer: conforms ANY evaluation source "
        "— compiled binary, external solver (FEM/CFD), a dataset with an odd "
        "convention, raw physics, or a plain-language spec — into one "
        "validated f3dasm DataGenerator, plus a registration manifest so the "
        "runtime registers it as the canonical oracle. Validates on one "
        "sample; does not run experiments or optimize."
    )
    report_sections = (
        "### Actions taken",
        "### Conclusions",
        "### Numbers",
        "### Retrospective",
    )
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
system_prompt = DATA_GENERATOR_SYSTEM_PROMPT class-attribute instance-attribute #
tools = frozenset({'Bash', 'Edit', 'Read', 'Write', 'Glob', 'Grep', 'ReportEvals', 'QueryStore', 'OracleStatus', 'HypothesisList', 'BashOutput', 'KillShell', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = True class-attribute instance-attribute #
role = 'datagenerator' class-attribute instance-attribute #
description = 'The universal oracle standardizer: conforms ANY evaluation source — compiled binary, external solver (FEM/CFD), a dataset with an odd convention, raw physics, or a plain-language spec — into one validated f3dasm DataGenerator, plus a registration manifest so the runtime registers it as the canonical oracle. Validates on one sample; does not run experiments or optimize.' class-attribute instance-attribute #
report_sections = ('### Actions taken', '### Conclusions', '### Numbers', '### Retrospective') class-attribute instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir, delegation_id=None, lit_reviewer_notes_dir=None) -> dict #

Base corpus tools, plus the on-demand f3dasm API lookup.

Only the two agents that WRITE f3dasm carry this tool. Every tool costs catalog tokens in every model call for the agent holding it, so a lookup the critic and strategizer never need does not go to them.

super() is called, so the literature-corpus tools survive: this agent wants papers for methodology AND the API for mechanics.

Source code in src/adda/_src/agents/datagenerator.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def build_closure_tools(
    self,
    study_dir,
    delegation_id=None,
    lit_reviewer_notes_dir=None,
) -> dict:
    """Base corpus tools, plus the on-demand f3dasm API lookup.

    Only the two agents that WRITE f3dasm carry this tool. Every tool costs
    catalog tokens in every model call for the agent holding it, so a
    lookup the critic and strategizer never need does not go to them.

    super() is called, so the literature-corpus tools survive: this agent
    wants papers for methodology AND the API for mechanics.
    """
    tools = super().build_closure_tools(
        study_dir,
        delegation_id=delegation_id,
        lit_reviewer_notes_dir=lit_reviewer_notes_dir,
    ) or {}
    from ..knowledge.f3dasm_api import build_f3dasm_api_closures
    tools.update(build_f3dasm_api_closures())
    return tools

adda.AbaqusDataGeneratorAgent #

DataGeneratorAgent that can read the Abaqus reference manual.

Set ADDA_ABAQUS_DOC_CORPUS to a corpus directory, or pass corpus_dir= to the constructor. With neither, the tool is WITHHELD and this agent is indistinguishable from its base class -- see build_abaqus_docs_closures for why that is safer than declaring a tool that cannot answer.

Source code in src/adda/_src/agents/abaqus_datagenerator.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class AbaqusDataGeneratorAgent(DataGeneratorAgent):
    """DataGeneratorAgent that can read the Abaqus reference manual.

    Set ``ADDA_ABAQUS_DOC_CORPUS`` to a corpus directory, or pass
    ``corpus_dir=`` to the constructor. With neither, the tool is WITHHELD and
    this agent is indistinguishable from its base class -- see
    ``build_abaqus_docs_closures`` for why that is safer than declaring a tool
    that cannot answer.
    """

    role = "datagenerator"

    def __init__(self, *args, corpus_dir=None, **kwargs):
        super().__init__(*args, **kwargs)
        self._abaqus_corpus_dir = corpus_dir

    def build_closure_tools(
        self,
        study_dir,
        delegation_id=None,
        lit_reviewer_notes_dir=None,
    ) -> dict:
        """Inherited tools plus ConsultAbaqus.

        super() IS called, so the literature-corpus tools and the f3dasm API
        lookup survive: this agent wants papers for methodology, the f3dasm
        API for plumbing, and the solver manual for mechanics.
        """
        tools = super().build_closure_tools(
            study_dir,
            delegation_id=delegation_id,
            lit_reviewer_notes_dir=lit_reviewer_notes_dir,
        ) or {}
        from ..knowledge.abaqus import build_abaqus_docs_closures
        tools.update(build_abaqus_docs_closures(self._abaqus_corpus_dir))
        return tools
system_prompt = DATA_GENERATOR_SYSTEM_PROMPT class-attribute instance-attribute #
tools = frozenset({'Bash', 'Edit', 'Read', 'Write', 'Glob', 'Grep', 'ReportEvals', 'QueryStore', 'OracleStatus', 'HypothesisList', 'BashOutput', 'KillShell', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = True class-attribute instance-attribute #
description = 'The universal oracle standardizer: conforms ANY evaluation source — compiled binary, external solver (FEM/CFD), a dataset with an odd convention, raw physics, or a plain-language spec — into one validated f3dasm DataGenerator, plus a registration manifest so the runtime registers it as the canonical oracle. Validates on one sample; does not run experiments or optimize.' class-attribute instance-attribute #
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
report_sections = ('### Actions taken', '### Conclusions', '### Numbers', '### Retrospective') class-attribute instance-attribute #
role = 'datagenerator' class-attribute instance-attribute #
_abaqus_corpus_dir = corpus_dir instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir, delegation_id=None, lit_reviewer_notes_dir=None) -> dict #

Inherited tools plus ConsultAbaqus.

super() IS called, so the literature-corpus tools and the f3dasm API lookup survive: this agent wants papers for methodology, the f3dasm API for plumbing, and the solver manual for mechanics.

Source code in src/adda/_src/agents/abaqus_datagenerator.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def build_closure_tools(
    self,
    study_dir,
    delegation_id=None,
    lit_reviewer_notes_dir=None,
) -> dict:
    """Inherited tools plus ConsultAbaqus.

    super() IS called, so the literature-corpus tools and the f3dasm API
    lookup survive: this agent wants papers for methodology, the f3dasm
    API for plumbing, and the solver manual for mechanics.
    """
    tools = super().build_closure_tools(
        study_dir,
        delegation_id=delegation_id,
        lit_reviewer_notes_dir=lit_reviewer_notes_dir,
    ) or {}
    from ..knowledge.abaqus import build_abaqus_docs_closures
    tools.update(build_abaqus_docs_closures(self._abaqus_corpus_dir))
    return tools

adda.BasiliskDataGeneratorAgent #

DataGeneratorAgent that can read the Basilisk source tree.

Set ADDA_BASILISK_SRC to a Basilisk checkout (the directory containing src/), or pass corpus_dir= to the constructor. With neither, the tool is WITHHELD and this agent is indistinguishable from its base class -- see build_basilisk_docs_closures for why that is safer than declaring a tool that cannot answer.

Source code in src/adda/_src/agents/basilisk_datagenerator.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class BasiliskDataGeneratorAgent(DataGeneratorAgent):
    """DataGeneratorAgent that can read the Basilisk source tree.

    Set ``ADDA_BASILISK_SRC`` to a Basilisk checkout (the directory containing
    ``src/``), or pass ``corpus_dir=`` to the constructor. With neither, the
    tool is WITHHELD and this agent is indistinguishable from its base class --
    see ``build_basilisk_docs_closures`` for why that is safer than declaring
    a tool that cannot answer.
    """

    role = "datagenerator"

    def __init__(self, *args, corpus_dir=None, **kwargs):
        super().__init__(*args, **kwargs)
        self._basilisk_corpus_dir = corpus_dir

    def build_closure_tools(
        self,
        study_dir,
        delegation_id=None,
        lit_reviewer_notes_dir=None,
    ) -> dict:
        """Inherited tools plus ConsultBasilisk.

        super() IS called, so the literature-corpus tools and the f3dasm API
        lookup survive: this agent wants papers for methodology, the f3dasm
        API for plumbing, and the Basilisk tree for the simulation itself.
        """
        tools = super().build_closure_tools(
            study_dir,
            delegation_id=delegation_id,
            lit_reviewer_notes_dir=lit_reviewer_notes_dir,
        ) or {}
        from ..knowledge.basilisk import build_basilisk_docs_closures
        tools.update(build_basilisk_docs_closures(self._basilisk_corpus_dir))
        return tools
system_prompt = DATA_GENERATOR_SYSTEM_PROMPT class-attribute instance-attribute #
tools = frozenset({'Bash', 'Edit', 'Read', 'Write', 'Glob', 'Grep', 'ReportEvals', 'QueryStore', 'OracleStatus', 'HypothesisList', 'BashOutput', 'KillShell', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = True class-attribute instance-attribute #
description = 'The universal oracle standardizer: conforms ANY evaluation source — compiled binary, external solver (FEM/CFD), a dataset with an odd convention, raw physics, or a plain-language spec — into one validated f3dasm DataGenerator, plus a registration manifest so the runtime registers it as the canonical oracle. Validates on one sample; does not run experiments or optimize.' class-attribute instance-attribute #
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
report_sections = ('### Actions taken', '### Conclusions', '### Numbers', '### Retrospective') class-attribute instance-attribute #
role = 'datagenerator' class-attribute instance-attribute #
_basilisk_corpus_dir = corpus_dir instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir, delegation_id=None, lit_reviewer_notes_dir=None) -> dict #

Inherited tools plus ConsultBasilisk.

super() IS called, so the literature-corpus tools and the f3dasm API lookup survive: this agent wants papers for methodology, the f3dasm API for plumbing, and the Basilisk tree for the simulation itself.

Source code in src/adda/_src/agents/basilisk_datagenerator.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def build_closure_tools(
    self,
    study_dir,
    delegation_id=None,
    lit_reviewer_notes_dir=None,
) -> dict:
    """Inherited tools plus ConsultBasilisk.

    super() IS called, so the literature-corpus tools and the f3dasm API
    lookup survive: this agent wants papers for methodology, the f3dasm
    API for plumbing, and the Basilisk tree for the simulation itself.
    """
    tools = super().build_closure_tools(
        study_dir,
        delegation_id=delegation_id,
        lit_reviewer_notes_dir=lit_reviewer_notes_dir,
    ) or {}
    from ..knowledge.basilisk import build_basilisk_docs_closures
    tools.update(build_basilisk_docs_closures(self._basilisk_corpus_dir))
    return tools

adda.LiteratureReviewAgent #

Literature reviewer: answers epistemic questions from a corpus.

Owns runs/lit_reviewer_notes/corpus.csv and papers/ — study-scoped, shared and persisted across every run of the study, not per-run. Never answers from memory — all claims must cite exact passages. Calls ReadProblemStatement() itself for research-domain framing — every agent has this tool uniformly now, not just this one by declaration.

Source code in src/adda/_src/agents/literature.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
class LiteratureReviewAgent(Agent):
    """Literature reviewer: answers epistemic questions from a corpus.

    Owns runs/lit_reviewer_notes/corpus.csv and papers/ — study-scoped,
    shared and persisted across every run of the study, not per-run.
    Never answers from memory — all claims must cite exact passages.
    Calls ReadProblemStatement() itself for research-domain framing — every
    agent has this tool uniformly now, not just this one by declaration.
    """

    # Declare the role explicitly — the base default is "implementer", and
    # inheriting it makes implementer-only logic (the eval-parallelism
    # resource nudge, role telemetry) mis-fire on the literature reviewer.
    role = "literature_reviewer"
    tools = frozenset({"Read", "Grep", "Glob", "ReadProblemStatement"})
    reset_on_checkpoint = True
    description = (
        "Searches and synthesises primary scientific literature to"
        " answer epistemic questions: what methods exist, what has"
        " been tried, what the field recommends. Use before committing"
        " to a strategy you are uncertain about, or when you need to"
        " know the state of the art. Never for questions answerable"
        " from workspace data."
    )
    report_sections = (
        "### Papers reviewed",
        "### Key findings",
        "### Conclusions",
        "### Numbers",
        "### Retrospective",
    )
    mcp_servers = {}
    extra_allowed_tools = frozenset()

    system_prompt = LITERATURE_REVIEW_SYSTEM_PROMPT

    def build_closure_tools(
        self,
        study_dir,
        delegation_id=None,
        lit_reviewer_notes_dir=None,
    ):
        """Inject corpus + discovery tools as runtime closures."""
        return build_literature_tools(study_dir, lit_reviewer_notes_dir)
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
role = 'literature_reviewer' class-attribute instance-attribute #
tools = frozenset({'Read', 'Grep', 'Glob', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = True class-attribute instance-attribute #
description = 'Searches and synthesises primary scientific literature to answer epistemic questions: what methods exist, what has been tried, what the field recommends. Use before committing to a strategy you are uncertain about, or when you need to know the state of the art. Never for questions answerable from workspace data.' class-attribute instance-attribute #
report_sections = ('### Papers reviewed', '### Key findings', '### Conclusions', '### Numbers', '### Retrospective') class-attribute instance-attribute #
mcp_servers = {} class-attribute instance-attribute #
extra_allowed_tools = frozenset() class-attribute instance-attribute #
system_prompt = LITERATURE_REVIEW_SYSTEM_PROMPT class-attribute instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir, delegation_id=None, lit_reviewer_notes_dir=None) #

Inject corpus + discovery tools as runtime closures.

Source code in src/adda/_src/agents/literature.py
158
159
160
161
162
163
164
165
def build_closure_tools(
    self,
    study_dir,
    delegation_id=None,
    lit_reviewer_notes_dir=None,
):
    """Inject corpus + discovery tools as runtime closures."""
    return build_literature_tools(study_dir, lit_reviewer_notes_dir)

adda.AdversarialCritiqueAgent #

Adversarial peer-reviewer agent.

Reads the strategizer's notes and workspace outputs, then returns a structured critique whose prior is that the current conclusion is wrong. Findings are labelled CRITICAL / MAJOR / MINOR with a final PASS / REVISE / REJECT verdict.

Pure read-only: Read + Glob + Grep + ConsultHandbook (universally injected) + QueryStore/OracleStatus/HypothesisList (store/hypothesis access), no write or execution tools.

Source code in src/adda/_src/agents/critic.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
class AdversarialCritiqueAgent(Agent):
    """Adversarial peer-reviewer agent.

    Reads the strategizer's notes and workspace outputs, then returns a
    structured critique whose prior is that the current conclusion is wrong.
    Findings are labelled CRITICAL / MAJOR / MINOR with a final PASS /
    REVISE / REJECT verdict.

    Pure read-only: Read + Glob + Grep + ConsultHandbook (universally
    injected) + QueryStore/OracleStatus/HypothesisList
    (store/hypothesis access), no write or execution tools.
    """

    system_prompt = ADVERSARIAL_CRITIQUE_SYSTEM_PROMPT
    # Read-only ledger/store tools let the critic verify the headline against
    # the actual ledger rows and check hypothesis verdicts directly, instead of
    # re-deriving them by hand from raw files. Read-only — it never mutates.
    tools = frozenset({"Read", "Glob", "Grep",
                       "QueryStore", "OracleStatus",
                       "HypothesisList",
                       "ReadProblemStatement"})
    reset_on_checkpoint = True
    role = "critic"
    description = (
        "Adversarial quality auditor. "
        "Verifies conclusions are well-evidenced, hypotheses are self-consistent, "
        "and deliverables match PROBLEM_STATEMENT requirements."
    )
    report_sections = (
        "### Actions taken",
        "### Findings",
        "### Verdict",
        "### Numbers",
        "### Retrospective",
    )
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
system_prompt = ADVERSARIAL_CRITIQUE_SYSTEM_PROMPT class-attribute instance-attribute #
tools = frozenset({'Read', 'Glob', 'Grep', 'QueryStore', 'OracleStatus', 'HypothesisList', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = True class-attribute instance-attribute #
role = 'critic' class-attribute instance-attribute #
description = 'Adversarial quality auditor. Verifies conclusions are well-evidenced, hypotheses are self-consistent, and deliverables match PROBLEM_STATEMENT requirements.' class-attribute instance-attribute #
report_sections = ('### Actions taken', '### Findings', '### Verdict', '### Numbers', '### Retrospective') class-attribute instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir: Path, delegation_id: str | None = None, lit_reviewer_notes_dir: Path | None = None) -> dict #

Return runtime closure tools for this agent.

Called by the runtime when constructing the worker adapter so agents can inject Python callables (e.g. corpus management tools) without declaring them in Agent.tools.

The default gives EVERY agent read-only lookup against the study's persistent literature corpus (ConsultLiterature) — the corpus is shared, queryable infrastructure (see LiteratureCorpus), the same way QueryStore lets every node read the canonical evaluation ledger without delegating to the data generator. ACQUIRING a new paper (CorpusAdd, external search) stays literature_reviewer-only: finding and vetting a new paper needs judgment a raw tool call can't supply, so it stays gated behind an actual delegation — see LiteratureReviewAgent.build_closure_tools, which overrides this method entirely (the same ConsultLiterature plus CorpusAdd) and does not call super().

Override in a subclass to replace this default entirely.

Source code in src/adda/_src/backends/base.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def build_closure_tools(
    self,
    study_dir: Path,
    delegation_id: str | None = None,
    lit_reviewer_notes_dir: Path | None = None,
) -> dict:
    """Return runtime closure tools for this agent.

    Called by the runtime when constructing the worker adapter so agents can
    inject Python callables (e.g. corpus management tools) without declaring
    them in Agent.tools.

    The default gives EVERY agent read-only lookup against the study's
    persistent literature corpus (ConsultLiterature) —
    the corpus is shared, queryable infrastructure (see LiteratureCorpus),
    the same way QueryStore lets every node read the canonical evaluation
    ledger without delegating to the data generator. ACQUIRING a new paper
    (CorpusAdd, external search) stays literature_reviewer-only: finding
    and vetting a new paper needs judgment a raw tool call can't supply,
    so it stays gated behind an actual delegation — see
    LiteratureReviewAgent.build_closure_tools, which overrides this
    method entirely (the same ConsultLiterature plus CorpusAdd) and
    does not call super().

    Override in a subclass to replace this default entirely.
    """
    from pathlib import Path as _Path

    try:
        from ..literature.literature_corpus import LiteratureCorpus
    except ImportError:
        return {}

    corpus_dir = (
        _Path(lit_reviewer_notes_dir) if lit_reviewer_notes_dir is not None
        else _Path(study_dir) / "runs" / "lit_reviewer_notes"
    )
    corpus = LiteratureCorpus(corpus_dir)
    from ..agents.literature_tools.corpus import build_corpus_read_closures
    return build_corpus_read_closures(corpus)

adda.DebuggerAgent #

Specialist agent for diagnosing and tracing bugs.

Receives a failing command or traceback from the Strategizer, reproduces the failure, traces it to its root cause, and optionally applies a minimal fix. Returns a structured Report with root_cause and fix_applied numbers.

Source code in src/adda/_src/agents/debugger.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
class DebuggerAgent(Agent):
    """Specialist agent for diagnosing and tracing bugs.

    Receives a failing command or traceback from the Strategizer, reproduces
    the failure, traces it to its root cause, and optionally applies a minimal
    fix.  Returns a structured Report with root_cause and fix_applied numbers.
    """

    system_prompt = DEBUGGER_SYSTEM_PROMPT
    # Declare the role explicitly — inheriting the base "implementer" default
    # makes implementer-only logic mis-fire on the debugger.
    role = "debugger"
    tools = frozenset({"Bash", "Read", "Grep", "Edit", "Write",
                       # read-only ledger/store access for diagnosis
                       "QueryStore", "OracleStatus",
                       "HypothesisList",
                       # manage a backgrounded job: poll it / stop it
                       "BashOutput", "KillShell",
                       "ReadProblemStatement"})
    reset_on_checkpoint = True
    description = (
        "Diagnoses errors and applies minimal fixes. "
        "Use when a delegation returns a traceback or failure that needs root-cause analysis."
    )
    report_sections = (
        "### Root cause",
        "### Fix applied",
        "### Conclusions",
        "### Numbers",
    )
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
system_prompt = DEBUGGER_SYSTEM_PROMPT class-attribute instance-attribute #
role = 'debugger' class-attribute instance-attribute #
tools = frozenset({'Bash', 'Read', 'Grep', 'Edit', 'Write', 'QueryStore', 'OracleStatus', 'HypothesisList', 'BashOutput', 'KillShell', 'ReadProblemStatement'}) class-attribute instance-attribute #
reset_on_checkpoint = True class-attribute instance-attribute #
description = 'Diagnoses errors and applies minimal fixes. Use when a delegation returns a traceback or failure that needs root-cause analysis.' class-attribute instance-attribute #
report_sections = ('### Root cause', '### Fix applied', '### Conclusions', '### Numbers') class-attribute instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir: Path, delegation_id: str | None = None, lit_reviewer_notes_dir: Path | None = None) -> dict #

Return runtime closure tools for this agent.

Called by the runtime when constructing the worker adapter so agents can inject Python callables (e.g. corpus management tools) without declaring them in Agent.tools.

The default gives EVERY agent read-only lookup against the study's persistent literature corpus (ConsultLiterature) — the corpus is shared, queryable infrastructure (see LiteratureCorpus), the same way QueryStore lets every node read the canonical evaluation ledger without delegating to the data generator. ACQUIRING a new paper (CorpusAdd, external search) stays literature_reviewer-only: finding and vetting a new paper needs judgment a raw tool call can't supply, so it stays gated behind an actual delegation — see LiteratureReviewAgent.build_closure_tools, which overrides this method entirely (the same ConsultLiterature plus CorpusAdd) and does not call super().

Override in a subclass to replace this default entirely.

Source code in src/adda/_src/backends/base.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def build_closure_tools(
    self,
    study_dir: Path,
    delegation_id: str | None = None,
    lit_reviewer_notes_dir: Path | None = None,
) -> dict:
    """Return runtime closure tools for this agent.

    Called by the runtime when constructing the worker adapter so agents can
    inject Python callables (e.g. corpus management tools) without declaring
    them in Agent.tools.

    The default gives EVERY agent read-only lookup against the study's
    persistent literature corpus (ConsultLiterature) —
    the corpus is shared, queryable infrastructure (see LiteratureCorpus),
    the same way QueryStore lets every node read the canonical evaluation
    ledger without delegating to the data generator. ACQUIRING a new paper
    (CorpusAdd, external search) stays literature_reviewer-only: finding
    and vetting a new paper needs judgment a raw tool call can't supply,
    so it stays gated behind an actual delegation — see
    LiteratureReviewAgent.build_closure_tools, which overrides this
    method entirely (the same ConsultLiterature plus CorpusAdd) and
    does not call super().

    Override in a subclass to replace this default entirely.
    """
    from pathlib import Path as _Path

    try:
        from ..literature.literature_corpus import LiteratureCorpus
    except ImportError:
        return {}

    corpus_dir = (
        _Path(lit_reviewer_notes_dir) if lit_reviewer_notes_dir is not None
        else _Path(study_dir) / "runs" / "lit_reviewer_notes"
    )
    corpus = LiteratureCorpus(corpus_dir)
    from ..agents.literature_tools.corpus import build_corpus_read_closures
    return build_corpus_read_closures(corpus)

adda.MathExpertAgent #

Specialist agent for verified symbolic derivations.

Authors and runs a Workspace-backed derivation script, mechanically checking every equality/domain/dimensional claim it makes via SymPy and reporting a genuine three-valued verdict (never coercing INCONCLUSIVE to either pole). Assumptions and other unverified claims are recorded via assume() with an ASSERTED verdict, never adjudicated. Does NOT justify why an assumption is physically valid, does NOT build the physics DataGenerator Block, and is NOT part of the default graph.

Source code in src/adda/_src/agents/math_expert.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
class MathExpertAgent(Agent):
    """Specialist agent for verified symbolic derivations.

    Authors and runs a Workspace-backed derivation script, mechanically
    checking every equality/domain/dimensional claim it makes via SymPy and
    reporting a genuine three-valued verdict (never coercing INCONCLUSIVE
    to either pole). Assumptions and other unverified claims are recorded
    via assume() with an ASSERTED verdict, never adjudicated. Does NOT
    justify why an assumption is physically valid, does NOT build the
    physics DataGenerator Block, and is NOT part of the default graph.
    """

    system_prompt = MATH_EXPERT_SYSTEM_PROMPT
    # No "Write": the generic Write tool is hard-sandboxed to this
    # delegation's OWN debug/delegations/D###/ folder (worker.py's
    # _setup_sandboxed_write), but MathExpert's durable output always lives
    # in the SHARED study_dir/runs/math_workspace/ -- Write can never reach
    # it, only ever fail. Confirmed twice in real dogfooding runs (Ollama,
    # Qwen3.8:27b): the model reflexively tried Write first, got rejected,
    # then self-corrected to Bash -- costing a wasted turn each time, for a
    # tool with no legitimate target here at all. Edit is NOT sandboxed the
    # same way (plain native tool, no delegation-id restriction) and stays.
    tools = frozenset({
        "Bash", "Edit", "Read", "Glob", "Grep",
        # read-only ledger/study context, same set the implementer gets
        "QueryStore", "HypothesisList",
        "ReadProblemStatement",
    })
    role = "math_expert"
    description = (
        "Derives and mechanically verifies symbolic math via SymPy "
        "(Workspace scripts under runs/math_workspace/); reports "
        "CONFIRMED/REFUTED/INCONCLUSIVE per claim, never a restated "
        "confidence. Use when a modeling decision needs its algebraic "
        "consequences checked, or a published derivation needs "
        "transcribing/extending."
    )
    report_sections = (
        "### Actions taken",
        "### Verified Derivation",
        "### Conclusions",
        "### Numbers",
        "### Retrospective",
    )
reset_on_checkpoint: bool = True class-attribute instance-attribute #
model: str | None = None class-attribute instance-attribute #
backend: str | None = None class-attribute instance-attribute #
base_url: str | None = None class-attribute instance-attribute #
base_prompt: str | None = None class-attribute instance-attribute #
mcp_servers: dict = {} class-attribute instance-attribute #
extra_allowed_tools: frozenset[str] = frozenset() class-attribute instance-attribute #
max_history_pairs: int = 5 class-attribute instance-attribute #
system_prompt = MATH_EXPERT_SYSTEM_PROMPT class-attribute instance-attribute #
tools = frozenset({'Bash', 'Edit', 'Read', 'Glob', 'Grep', 'QueryStore', 'HypothesisList', 'ReadProblemStatement'}) class-attribute instance-attribute #
role = 'math_expert' class-attribute instance-attribute #
description = 'Derives and mechanically verifies symbolic math via SymPy (Workspace scripts under runs/math_workspace/); reports CONFIRMED/REFUTED/INCONCLUSIVE per claim, never a restated confidence. Use when a modeling decision needs its algebraic consequences checked, or a published derivation needs transcribing/extending.' class-attribute instance-attribute #
report_sections = ('### Actions taken', '### Verified Derivation', '### Conclusions', '### Numbers', '### Retrospective') class-attribute instance-attribute #
forward() -> None #

ADAS hook — override for inspectable Python orchestration.

Source code in src/adda/_src/backends/base.py
324
325
def forward(self) -> None:
    """ADAS hook — override for inspectable Python orchestration."""
build_closure_tools(study_dir: Path, delegation_id: str | None = None, lit_reviewer_notes_dir: Path | None = None) -> dict #

Return runtime closure tools for this agent.

Called by the runtime when constructing the worker adapter so agents can inject Python callables (e.g. corpus management tools) without declaring them in Agent.tools.

The default gives EVERY agent read-only lookup against the study's persistent literature corpus (ConsultLiterature) — the corpus is shared, queryable infrastructure (see LiteratureCorpus), the same way QueryStore lets every node read the canonical evaluation ledger without delegating to the data generator. ACQUIRING a new paper (CorpusAdd, external search) stays literature_reviewer-only: finding and vetting a new paper needs judgment a raw tool call can't supply, so it stays gated behind an actual delegation — see LiteratureReviewAgent.build_closure_tools, which overrides this method entirely (the same ConsultLiterature plus CorpusAdd) and does not call super().

Override in a subclass to replace this default entirely.

Source code in src/adda/_src/backends/base.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def build_closure_tools(
    self,
    study_dir: Path,
    delegation_id: str | None = None,
    lit_reviewer_notes_dir: Path | None = None,
) -> dict:
    """Return runtime closure tools for this agent.

    Called by the runtime when constructing the worker adapter so agents can
    inject Python callables (e.g. corpus management tools) without declaring
    them in Agent.tools.

    The default gives EVERY agent read-only lookup against the study's
    persistent literature corpus (ConsultLiterature) —
    the corpus is shared, queryable infrastructure (see LiteratureCorpus),
    the same way QueryStore lets every node read the canonical evaluation
    ledger without delegating to the data generator. ACQUIRING a new paper
    (CorpusAdd, external search) stays literature_reviewer-only: finding
    and vetting a new paper needs judgment a raw tool call can't supply,
    so it stays gated behind an actual delegation — see
    LiteratureReviewAgent.build_closure_tools, which overrides this
    method entirely (the same ConsultLiterature plus CorpusAdd) and
    does not call super().

    Override in a subclass to replace this default entirely.
    """
    from pathlib import Path as _Path

    try:
        from ..literature.literature_corpus import LiteratureCorpus
    except ImportError:
        return {}

    corpus_dir = (
        _Path(lit_reviewer_notes_dir) if lit_reviewer_notes_dir is not None
        else _Path(study_dir) / "runs" / "lit_reviewer_notes"
    )
    corpus = LiteratureCorpus(corpus_dir)
    from ..agents.literature_tools.corpus import build_corpus_read_closures
    return build_corpus_read_closures(corpus)