English · Español
Lab 00 — Typed Tools¶
Goal: implement the four §A13 tools as plain Python functions with JSON-Schema descriptors. No MCP yet — just the tools.
Estimated time: 2–3 hours.
Prereq: Phase 12's §A13 conjugation truth table available as
data/processed/conjugation_table.json(or wherever Phase 12 produced it).
What you produce¶
A directory experiments/31-typed-tools/ containing:
demo.py— instantiates each tool and prints a small smoke-test transcript.results.json—{tools_registered: 4, smoke_test_pass: true}.manifest.json— perLYNX_CORTEX.md§5.
Plus, in src/miniagent/tools/:
__init__.py— registry +@registerdecorator.base.py—Tooldataclass.conjugate.py— implementsconjugate.lookup_irregular_verb.py— implementslookup_irregular_verb.lookup_spanish.py— implementslookup_spanish.check_subject_verb_agreement.py— implementscheck_subject_verb_agreement.
TODOs¶
Block A — the Tool dataclass¶
In src/miniagent/tools/base.py:
- Define a frozen dataclass:
- Define a
ToolErrorexception type for tool-level errors (out-of-scope inputs, missing data). - Define a
registerdecorator that takesname,description, andinput_schemakeyword arguments and adds the wrapped function toregistered_toolsin__init__.py.
Block B — conjugate¶
In src/miniagent/tools/conjugate.py:
-
@register(name="conjugate", description="Return the conjugated form of an English verb.", input_schema={...})on a function: - Validate args against the §A13 enums; raise
ToolErrorif out of scope. - Look up the form in
data/processed/conjugation_table.json(or import it as a Python dict). - Return the conjugated string. E.g.
conjugate("eat", "past_simple", "3sg")returns"ate". - Test exhaustively: 20 verbs × 5 tenses × 3 persons = 300 combinations. All must round-trip.
Block C — lookup_irregular_verb¶
In src/miniagent/tools/lookup_irregular_verb.py:
- Signature:
lookup_irregular_verb(verb: str) -> dict. - Returns
{"infinitive": ..., "past_simple": ..., "past_participle": ..., "is_irregular": true}for the 8 irregular verbs (be, have, do, go, come, see, eat, write). - For a regular verb (one of the 12), returns
{"is_irregular": false}— useful so the agent can ask "is this irregular?" before committing to a lookup path. - For an out-of-scope verb, raises
ToolError.
Block D — lookup_spanish¶
In src/miniagent/tools/lookup_spanish.py:
- Signature:
lookup_spanish(english_form: str) -> str. -
english_formis the conjugated form (e.g.,"ate", not"eat"). - Returns the canonical Spanish translation (peninsular Spanish, tú-form, simple past — see
PHASE_31_PLAN.md§5 pitfall 6). - For an out-of-scope form, raises
ToolError.
Block E — check_subject_verb_agreement¶
In src/miniagent/tools/check_subject_verb_agreement.py:
- Signature:
check_subject_verb_agreement(subject: str, verb_form: str) -> dict. -
subjectis a pronoun:"I","you","he","she","it". (Plural pronouns are out of §A13 scope; return aToolError.) -
verb_formis a conjugated English form. - Returns
{"agrees": bool, "expected_form": str | None}.expected_formis filled whenagrees=false, naming the conjugated form that would agree.
Example: check_subject_verb_agreement("he", "go") returns {"agrees": false, "expected_form": "goes"}. check_subject_verb_agreement("he", "goes") returns {"agrees": true, "expected_form": null}.
Block F — tests¶
In tests/test_miniagent_tools.py:
-
test_conjugate_round_trip— 300 cases, all match the truth table. -
test_conjugate_out_of_scope_raises—conjugate("run", "past_simple", "3sg")raisesToolError. -
test_lookup_irregular_verb_returns_principal_parts— all 8 irregulars present, with correct past_simple and past_participle. -
test_lookup_irregular_verb_marks_regulars—lookup_irregular_verb("work")returns{"is_irregular": false}. -
test_lookup_spanish_canonical—lookup_spanish("ate")returns"comió"(or whatever the truth table specifies for 3sg past). -
test_check_agreement_pos— agreeing cases returnagrees=true. -
test_check_agreement_neg_proposes_fix— disagreeing cases returnagrees=falsewith the correctexpected_form. -
test_check_agreement_plural_pronoun_out_of_scope—subject="we"raisesToolError.
Block G — smoke demo¶
In experiments/31-typed-tools/demo.py:
- Import
registered_toolsfromsrc.miniagent.tools. - Print each tool's
nameanddescription. - Call each tool with one canonical input; print result.
- Write
results.jsonwith{tools_registered, smoke_test_pass}.
Constraints¶
- No MCP yet. This lab is pure Python. Lab 01 introduces the protocol layer.
- Truth table is the contract. Phase 12 produced the data; tools read from it. Do not hand-code the conjugation grid inside the tool functions — that would let it drift from the corpus.
- No
pydanticrequirement. If Borja wants to add it for argument validation, fine; if not, stdlibdictvalidation is enough. - No I/O side effects. Tools read constants and compute. They do not write files, hit network, or call external services.
Stop conditions¶
Done when:
- All Block F tests pass.
demo.pyprints a clean transcript and writesresults.json.- Each tool's
input_schemavalidates withjsonschema.Draft7Validator(schema).check_schema()(sanity-check the schema is well-formed).
Pitfalls¶
- Hand-coded vs table-driven. Easy to start typing the conjugation grid inside
conjugate. Resist; pull from the truth table. - Spanish translation variants. Pick one canonical form per English form and document the choice. Variants (vos vs tú, peninsular vs Latin American) are explicit non-features.
- Pronoun normalization. "He" vs "he" vs "He.". Tools should lowercase + strip punctuation before comparing.
is_irregular: falseis not an error.lookup_irregular_verb("work")is a successful call returning a useful answer — not an exception.expected_formofnullwhen agreeing. Don't return an empty string; returnNone. Distinguish "no fix needed" from "fix is the empty string".
When to consult solutions/¶
After all Block F tests pass. The solution at solutions/00-typed-tools-ref.md (written at phase open) will cross-check the schema shapes; minor differences are fine but the test-truth-table mapping must match.
Next lab: lab/01-mcp-server.md.