Extension to free-text extraction #37
naliATsurf
started this conversation in
General
Replies: 1 comment
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Extension Plan: Free-Text (and Multi-Modality) Metadata Extraction
This document plans the extension of the framework to extract metadata from
free-text sources (plain text, Markdown; images/PDF later), reusing the
existing orchestrator, player, and standards machinery. It complements
Architecture and the Module Guide.
Status legend: ✅ done · 🟡 partial · 🔲 not started.
Motivation and approach
The
ExecutionContextabstraction was always meant to represent any "world"the agents operate in, not just tabular data. But the original base contract
leaked tabular assumptions:
read_resource() -> pd.DataFrame,FieldInfodtypes,
is_multi_csv. Rather than force every new modality to fake a table,the adopted approach is a capability split: keep a small modality-agnostic
base and push data-access shape into subclasses.
We extend, not fork: the orchestrator/planner/player pipeline is untouched
except where it rendered tabular vocabulary, and the work concentrates in
src/context/andsrc/tools/.Context module refactor ✅
Refactor the context module to accommodate multiple modalities. All of the
following is done and verified (smoke test +
python -m unittest discover tests; existing pipeline green).TabularContextsplit.ExecutionContextnow holds only themodality-agnostic contract (
resources,get_resource_info,get_schema,get_relationships,validate). The DataFrame contract (read_resource,iter_resource,get_field_values) moved to a newTabularContext(ExecutionContext).CSVContext/SQLiteContextsubclassit; behavior unchanged.
ResourceInfosplit into a universal base +TabularResourceInfo(fields, primary_key) +TextResourceInfo(char/word/line counts, language, encoding). Dropped the interim
propertiesbag. Each carries akinddiscriminator and overridesto_dict()andsummary(), so consumers render per-modality withoutbranching.
RelationshipInfo.from_field/to_fieldare now optional and it grew adescribe(); relationships can bewhole-resource (e.g.
"cites","shared-entity"), not only foreign keys.is_multi_csv→is_multi_resource(
len(resources) > 1), threaded throughplan_executor,step_executor,player,main, and the serializedto_dict()/get_schema()key. Thisalso fixed a latent bug: multi-document contexts had returned
is_multi_csv = False, so the planner silently treated multi-file textcorpora as single-resource. Deleted the unused
primary_resourceproperty.Phase 1 —
TextContext✅Implemented in
src/context/text_context.py(previously a placeholder).TextContextsubclassesExecutionContextdirectly (notTabularContext) — there is no DataFrame contract to satisfy. Data access isdocument-oriented:
read_text(resource, limit=None)— full text, cached.iter_chunks(resource, chunker=None)/get_chunks(resource)— yieldsTextChunk(resource, index, text, start_offset, char_count). Chunking is aread-time concern via a pluggable
chunkercallable; default isparagraph_chunker(blank-line split), withfixed_size_chunkerprovided.search(query, resource=None, regex=False, ...)— keyword/regex matcheswith surrounding context across one or all resources.
_load_resource_info()returns aTextResourceInfo(item_count = chunkcount, plus char/word/line counts, encoding, and a short extractive preview
in
description).Each input file is one resource, mirroring
CSVContext's str/list/dictnormalization.
_discover_relationships()uses the base default ([]) fornow — see Phase 5.
Phase 2 — Wiring: registry, classifier, factory ✅
registry.py:EXTENSION_MAPmaps.txt/.md/.markdown/.rst→ContextType.TEXT; addedis_text_type().context_classifier.py: directory and multi-path branches now recognizetext, so a folder or list of text files classifies as
TEXT. MixedCSV+text input classifies as
UNKNOWNrather than silently coercing.context_factory.py: dispatchesTextContextfor a single path, list,dict, or directory of text files.
Phase 3 — Text tools 🔲
The column-oriented tools in
src/tools/context_tools.py(field statistics,missing values, FK discovery, temporal/spatial column detection) are now
gated to tabular contexts (see Phase 4), but agents still have no
text-specific tools. Add a
src/tools/text_tools.py:get_sample_passages(context_key, resource, n)— representative chunks(head/middle/tail).
search_text(context_key, query, resource="")— wrapsTextContext.search.get_document_stats(context_key, resource)— chunk/word/character counts.detect_language(context_key, resource).extract_temporal_mentions/extract_spatial_mentions— dates and placenames found in the content, feeding the existing
spatial_temporal_specialistrole.Phase 4 — Players and planning 🟡
call
_get_tabular_context()and return a clear "requires a tabularcontext" message on text contexts;
get_sample_itemsis dual-mode (rows vs.chunks);
get_context_overviewserializesinfo.to_dict()polymorphically.Still open: declaring per-player tool applicability by
ContextTypeso theplanner never schedules a tabular tool against prose in the first place.
text_analystplayer 🔲. Add a role (or text-specific prompts fordata_analyst) that reasons in documents/passages, equipped with the Phase 3tools.
metadata_generator/critic/metadata_specialistarecontext-agnostic and carry over. Mention the text tools in the planner
prompt (
src/orchestrator/prompts.py).Phase 5 — Standards and output schema 🔲
Add a document-oriented standard to
STANDARD_DEFINITIONSinsrc/standards.py(working namedocument_general):title,description,subject,language,document_type,authors,temporal_coverage,spatial_coverage(textual),keywords. Existing standards stay selectable.Cross-document relationships (shared entities, citations) via an overridden
TextContext._discover_relationships()— theRelationshipInfogroundwork isalready in place (see Context module refactor).
Phase 6 — Tests, docs, demo 🔲
tests/(chunking,
TextResourceInfo, factory dispatch, classifier, tool gating),mirroring the CSV/SQLite structure.
examples/script running the pipeline over a small text corpus.src/context/section and the demoapp's accepted file types.
Friction points and notes
into a fake table; the capability split (base +
TabularContext+TextContext) removes that. New modalities add a subclass, not a shim.chunkerargument, so experiments need no code change.
isinstance(ctx, TabularContext). Fine for two modalities; if a thirdoverlaps (PDF = text + images), introduce explicit capability protocols /
a
capabilitiesset rather than a deep inheritance tree..txtis not always prose. A.txtfile may be delimited data; theclassifier may eventually want a content sniff (like
CSVContext'sdelimiter sniffing) rather than trusting the extension alone.
ContextTypeis a closed enum. AddingIMAGE/PDFis a one-lineedit there plus a registry mapping; acceptable, not a base-class concern.
Remaining order of work
The refactor and Phases 1–2 are done. Phase 3 (text tools) unblocks a real
agent run on text; then Phase 4's
text_analyst+ planner wiring; then Phase5 (standard) for useful output; Phase 6 (tests/example/docs) throughout.
Phases 3–5 are the minimum for a first end-to-end text extraction.
All reactions