feat: progressive disclosure for tool results — view registry + drilldown loop#100
Merged
feat: progressive disclosure for tool results — view registry + drilldown loop#100
Conversation
…wn loop (#17) - Add ViewRegistry class mapping content types to ViewSpec generators - Built-in generators for application/json, text/csv, text/plain, binary - Auto-generate ViewSpec entries in apply_firewall() and ingest_tool_result() - Add ContextManager.drilldown() with optional context injection - Add drilldown_tool_spec() helper for agent tool catalogs - Small tool outputs now stored in artifact store for drilldown support - Content-type detection heuristics for generic MIME types - 32 new tests in test_views.py, 12 new tests in test_manager.py
There was a problem hiding this comment.
Pull request overview
This PR implements the progressive disclosure loop for tool results, connecting ViewSpec, ViewRegistry, ArtifactStore.drilldown(), and ResultEnvelope.views into a usable agent-facing workflow. It closes issue #17 by wiring together the existing building blocks (which previously existed in isolation) into a cohesive agent-callable flow.
Changes:
- New
src/contextweaver/context/views.pymodule introducingViewRegistry, built-in MIME-type generators (_json_views,_csv_views,_text_views,_binary_views), content-type detection,generate_views(), anddrilldown_tool_spec() ContextManagergainsdrilldown()/drilldown_sync()methods and aview_registryproperty;ingest_tool_result()now stores all outputs (not just large ones) in the artifact store with auto-generated viewsapply_firewall()/apply_firewall_to_batch()extended with an optionalview_registryparameter to populateResultEnvelope.viewson the firewall path
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/contextweaver/context/views.py |
New module: ViewRegistry, view generators, content-type detection, drilldown_tool_spec() |
src/contextweaver/context/manager.py |
Adds drilldown(), view_registry property; stores small outputs in artifact store with views |
src/contextweaver/context/firewall.py |
Extends apply_firewall[_to_batch]() with optional view_registry to populate envelope.views |
src/contextweaver/context/__init__.py |
Exports ViewRegistry, generate_views, drilldown_tool_spec |
src/contextweaver/__init__.py |
Same top-level exports |
tests/test_views.py |
32 tests for generators, registry, detection, serialization, and tool spec |
tests/test_manager.py |
12 new integration tests for drilldown and auto-view generation |
CHANGELOG.md |
Changelog entries for all new public API additions |
You can also share your feedback on Copilot code review. Take the survey.
The previous selector {type: head, chars: 0} returned an empty string
on drilldown, making the Metadata view misleading. Changed to
{type: head, chars: 128} with label 'Header' so agents get useful
file magic bytes. Updated tests to match.
…deterministic False check
Repeated drilldown(inject=True) with the same handle and selector type previously crashed with ValueError due to duplicate IDs. Appending event_log.count() makes IDs unique and deterministic. Added test covering the repeated-inject scenario.
generate_views() now creates a fresh ViewRegistry() when none is provided, eliminating shared mutable state that could cause test pollution or non-deterministic behavior in multi-tenant scenarios.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Closes #17 — implements the progressive disclosure loop connecting
ViewSpec,ArtifactStore.drilldown(), andResultEnvelope.viewsinto a usable agent-facing workflow.New files
src/contextweaver/context/views.py— new module (287 lines):ViewRegistryclass mapping MIME content types toViewSpecgenerators_json_views,_csv_views,_text_views,_binary_viewsgenerate_views()convenience function (module-level default registry)drilldown_tool_spec()— returns aSelectableItemfor agent tool catalogs_detect_content_type()— heuristic content-type detection for generic MIME typestests/test_views.py— 32 tests covering all generators, registry, detection, and tool specModified files
src/contextweaver/context/firewall.py—apply_firewall()now accepts optionalview_registryparam, auto-generatesViewSpecentries and populatesenvelope.viewssrc/contextweaver/context/manager.py— added:ContextManager.drilldown()/drilldown_sync()— wrapsartifact_store.drilldown()with optional context injection (inject=Trueappends result asContextItem)ContextManager.view_registrypropertyingest_tool_result()now stored in artifact store with auto-generated viewssrc/contextweaver/context/__init__.py— exportsViewRegistry,generate_views,drilldown_tool_specsrc/contextweaver/__init__.py— same new exportstests/test_manager.py— 12 new tests: drilldown basic/json_keys/inject/sync/errors, auto-views on ingest, chained drilldownCHANGELOG.md— updated[Unreleased]Why
The building blocks for progressive disclosure existed (
ViewSpec,drilldown(),ResultEnvelope.views) but were not connected. Agents receivedResultEnvelopewith emptyviewsand no structured way to request follow-up slices. This change wires everything together:How verified
Tradeoffs / risks
application/octet-streamuses heuristics (JSON parse attempt, CSV sniffer). Conservative: falls back totext/plainfor decodable text, keeps original MIME for binary.text/*prefix matching falls through totext/plaingenerator (e.g.text/markdowngets line-based views).Acceptance criteria checklist
ViewSpecentries duringingest_tool_result()/ firewallContextManager.drilldown()methoddrilldown_tool_spec()helperResultEnvelope.viewspopulated automaticallyContextItementries