Audit fixes for agent-native architecture gaps: - agent_tools/content.py: parameterize healthy_threshold in check_embedding_quality - agent_tools/__init__.py: add __all__ exports and list_tools() runtime discovery - agent_tools/database.py: add CRUD primitives (create_motion, update_motion, delete_report) plus query_embeddings, query_similar_motions, query_compass_positions - tests/agent_tools/test_database_tools.py: add CRUD tool tests - tests/agent_tools/test_content_tools.py: add parameterized threshold test - tests/agent_tools/test_package.py: test list_tools() and package imports Tests: 245 passed, 3 skippedmain
parent
8af27bbf04
commit
efb3a8fbd2
@ -1 +1,119 @@ |
|||||||
"""Agent tools for Stemwijzer — atomic primitives for agent operation.""" |
"""Agent tools for Stemwijzer — atomic primitives for agent operation. |
||||||
|
|
||||||
|
Import individual modules or use `list_tools()` for runtime discovery. |
||||||
|
""" |
||||||
|
|
||||||
|
from __future__ import annotations |
||||||
|
|
||||||
|
from agent_tools.analysis import ( |
||||||
|
analyze_axis_stability, |
||||||
|
analyze_party_shift, |
||||||
|
validate_svd_labels, |
||||||
|
) |
||||||
|
from agent_tools.content import ( |
||||||
|
check_embedding_quality, |
||||||
|
suggest_svd_label, |
||||||
|
validate_layman_explanations, |
||||||
|
validate_motion_coverage, |
||||||
|
) |
||||||
|
from agent_tools.context import ( |
||||||
|
append_context_note, |
||||||
|
build_context, |
||||||
|
render_context_markdown, |
||||||
|
) |
||||||
|
from agent_tools.database import ( |
||||||
|
create_motion, |
||||||
|
delete_report, |
||||||
|
query_compass_positions, |
||||||
|
query_embeddings, |
||||||
|
query_motions, |
||||||
|
query_party_positions, |
||||||
|
query_pipeline_status, |
||||||
|
query_similar_motions, |
||||||
|
query_svd_vectors, |
||||||
|
query_votes, |
||||||
|
update_motion, |
||||||
|
) |
||||||
|
from agent_tools.pipeline import ( |
||||||
|
pipeline_check_health, |
||||||
|
pipeline_get_logs, |
||||||
|
pipeline_run_full, |
||||||
|
pipeline_run_stage, |
||||||
|
pipeline_validate_output, |
||||||
|
) |
||||||
|
from agent_tools.reports import generate_report |
||||||
|
|
||||||
|
__all__ = [ |
||||||
|
# Database |
||||||
|
"query_motions", |
||||||
|
"query_votes", |
||||||
|
"query_svd_vectors", |
||||||
|
"query_party_positions", |
||||||
|
"query_pipeline_status", |
||||||
|
"query_embeddings", |
||||||
|
"query_similar_motions", |
||||||
|
"query_compass_positions", |
||||||
|
"create_motion", |
||||||
|
"update_motion", |
||||||
|
"delete_report", |
||||||
|
# Pipeline |
||||||
|
"pipeline_run_stage", |
||||||
|
"pipeline_run_full", |
||||||
|
"pipeline_check_health", |
||||||
|
"pipeline_get_logs", |
||||||
|
"pipeline_validate_output", |
||||||
|
# Analysis |
||||||
|
"analyze_party_shift", |
||||||
|
"analyze_axis_stability", |
||||||
|
"validate_svd_labels", |
||||||
|
# Content |
||||||
|
"validate_motion_coverage", |
||||||
|
"validate_layman_explanations", |
||||||
|
"suggest_svd_label", |
||||||
|
"check_embedding_quality", |
||||||
|
# Reports |
||||||
|
"generate_report", |
||||||
|
# Context |
||||||
|
"build_context", |
||||||
|
"render_context_markdown", |
||||||
|
"append_context_note", |
||||||
|
# Discovery |
||||||
|
"list_tools", |
||||||
|
] |
||||||
|
|
||||||
|
|
||||||
|
def list_tools() -> list[dict[str, str]]: |
||||||
|
"""Return a list of all available agent tools with signatures and descriptions. |
||||||
|
|
||||||
|
Useful for runtime capability discovery and prompt injection. |
||||||
|
""" |
||||||
|
return [ |
||||||
|
{"name": "query_motions", "signature": "query_motions(db_path, limit=100, policy_area=None, start_date=None, end_date=None)", "description": "Query motions from the database with optional filters."}, |
||||||
|
{"name": "query_votes", "signature": "query_votes(db_path, motion_id=None, party=None)", "description": "Query vote counts or individual votes."}, |
||||||
|
{"name": "query_svd_vectors", "signature": "query_svd_vectors(db_path, window_id, entity_type='motion')", "description": "Query SVD vectors for a window and entity type."}, |
||||||
|
{"name": "query_party_positions", "signature": "query_party_positions(db_path, window_id='current_parliament')", "description": "Query party axis positions for a window."}, |
||||||
|
{"name": "query_pipeline_status", "signature": "query_pipeline_status(db_path)", "description": "Query pipeline freshness and coverage metrics."}, |
||||||
|
{"name": "query_embeddings", "signature": "query_embeddings(db_path, motion_id=None, model=None, limit=100)", "description": "Query text/fused embeddings."}, |
||||||
|
{"name": "query_similar_motions", "signature": "query_similar_motions(db_path, motion_id, top_k=10)", "description": "Query similar motions from similarity cache."}, |
||||||
|
{"name": "query_compass_positions", "signature": "query_compass_positions(db_path, window_id='current_parliament')", "description": "Query 2D compass positions for parties/MPs."}, |
||||||
|
{"name": "create_motion", "signature": "create_motion(db_path, title, description, date, policy_area='General', voting_results='[]')", "description": "Insert a new motion into the database."}, |
||||||
|
{"name": "update_motion", "signature": "update_motion(db_path, motion_id, **fields)", "description": "Update fields of an existing motion."}, |
||||||
|
{"name": "delete_report", "signature": "delete_report(output_path)", "description": "Delete a generated report file."}, |
||||||
|
{"name": "pipeline_run_stage", "signature": "pipeline_run_stage(db_path, stage, window_id, dry_run=False)", "description": "Run a single pipeline stage."}, |
||||||
|
{"name": "pipeline_run_full", "signature": "pipeline_run_full(db_path, dry_run=False)", "description": "Run the full pipeline end-to-end."}, |
||||||
|
{"name": "pipeline_check_health", "signature": "pipeline_check_health(db_path)", "description": "Run health checks and return report."}, |
||||||
|
{"name": "pipeline_get_logs", "signature": "pipeline_get_logs(stage, lines=50)", "description": "Retrieve recent log output for a stage."}, |
||||||
|
{"name": "pipeline_validate_output", "signature": "pipeline_validate_output(db_path, stage)", "description": "Validate that a stage produced expected output."}, |
||||||
|
{"name": "analyze_party_shift", "signature": "analyze_party_shift(db_path, party, window_start, window_end)", "description": "Compute party position shift between two windows."}, |
||||||
|
{"name": "analyze_axis_stability", "signature": "analyze_axis_stability(db_path, component, windows)", "description": "Compute axis stability across windows."}, |
||||||
|
{"name": "validate_svd_labels", "signature": "validate_svd_labels(db_path, component)", "description": "Compare SVD theme labels to actual party positions."}, |
||||||
|
{"name": "validate_motion_coverage", "signature": "validate_motion_coverage(db_path, start_date, end_date)", "description": "Check motion coverage for a date range."}, |
||||||
|
{"name": "validate_layman_explanations", "signature": "validate_layman_explanations(db_path, sample_size=50)", "description": "Sample motions and check explanation quality."}, |
||||||
|
{"name": "suggest_svd_label", "signature": "suggest_svd_label(db_path, component, top_n=10)", "description": "Suggest a label based on top/bottom motions."}, |
||||||
|
{"name": "check_embedding_quality", "signature": "check_embedding_quality(db_path, window_id, healthy_threshold=0.8)", "description": "Check embedding coverage for a window."}, |
||||||
|
{"name": "generate_report", "signature": "generate_report(db_path, report_type, parameters, output_path)", "description": "Generate a markdown report."}, |
||||||
|
{"name": "build_context", "signature": "build_context(db_path)", "description": "Build runtime context dict for the agent."}, |
||||||
|
{"name": "render_context_markdown", "signature": "render_context_markdown(db_path)", "description": "Render context as markdown for prompt injection."}, |
||||||
|
{"name": "append_context_note", "signature": "append_context_note(note)", "description": "Append a note to the accumulated agent knowledge."}, |
||||||
|
{"name": "list_tools", "signature": "list_tools()", "description": "Return a list of all available agent tools."}, |
||||||
|
] |
||||||
|
|||||||
@ -0,0 +1,39 @@ |
|||||||
|
"""Tests for agent_tools package-level utilities.""" |
||||||
|
|
||||||
|
import pytest |
||||||
|
|
||||||
|
|
||||||
|
class TestListTools: |
||||||
|
def test_returns_tool_list(self): |
||||||
|
from agent_tools import list_tools |
||||||
|
|
||||||
|
result = list_tools() |
||||||
|
assert isinstance(result, list) |
||||||
|
assert len(result) > 0 |
||||||
|
|
||||||
|
names = {t["name"] for t in result} |
||||||
|
assert "query_motions" in names |
||||||
|
assert "pipeline_check_health" in names |
||||||
|
assert "generate_report" in names |
||||||
|
assert "list_tools" in names |
||||||
|
|
||||||
|
def test_each_tool_has_required_fields(self): |
||||||
|
from agent_tools import list_tools |
||||||
|
|
||||||
|
result = list_tools() |
||||||
|
for tool in result: |
||||||
|
assert "name" in tool |
||||||
|
assert "signature" in tool |
||||||
|
assert "description" in tool |
||||||
|
|
||||||
|
|
||||||
|
class TestAllExports: |
||||||
|
def test_query_motions_importable(self): |
||||||
|
from agent_tools import query_motions |
||||||
|
|
||||||
|
assert callable(query_motions) |
||||||
|
|
||||||
|
def test_list_tools_importable(self): |
||||||
|
from agent_tools import list_tools |
||||||
|
|
||||||
|
assert callable(list_tools) |
||||||
Loading…
Reference in new issue