Skip to content

Abigail/conclusions level filter#851

Open
ajspig wants to merge 6 commits into
mainfrom
abigail/conclusions-level-filter
Open

Abigail/conclusions level filter#851
ajspig wants to merge 6 commits into
mainfrom
abigail/conclusions-level-filter

Conversation

@ajspig

@ajspig ajspig commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Conclusion responses now include a visible reasoning level (explicit, deductive, inductive, contradiction).
    • List and query now support filters (including filtering by level), with scope-managed fields protected from being overridden.
  • Documentation
    • Added a “Filtering Conclusions” section explaining level filtering and providing examples (including querying another peer’s conclusions).
  • Tests
    • Updated response expectations for level and added coverage for level filtering and reserved filter-key validation.

ajspig and others added 4 commits June 26, 2026 16:01
The `level` of a conclusion (explicit / deductive / inductive /
contradiction) was filterable server-side but stripped from the
`Conclusion` response and not surfaced in either SDK. This adds it
end-to-end so callers can list explicit-only ("not dreamed on")
conclusions without dropping to raw HTTP.

- api: add `level` to the Conclusion response schema
- python sdk: `ConclusionLevel` type, `level` on Conclusion/response,
  `level=` kwarg on ConclusionScope.list() and the async variant
- ts sdk: `ConclusionLevel` type, `level` on Conclusion/response,
  `level` option on list()
- tests: assert level is exposed; add level-filter list test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l= kwarg

Match the documented SDK convention (peers/sessions/messages all take a
generic `filters` dict passed through to the same dynamic server-side
filter logic) instead of a one-off `level=` kwarg. `level` filtering now
works as `list(filters={"level": "explicit"})` alongside any other
supported filter/operator.

The `level` field on the Conclusion response (added in the previous
commit) is kept — it's still not otherwise returned by the API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The branch's level-filter work exposed `filters=` on `list()` but left
`query()` (semantic search) hardcoding `{observer, observed}`, so callers
could filter the list endpoint by reasoning level but not semantic search —
asymmetric in both SDKs.

- Python: add keyword-only `filters` to `ConclusionScope.query` and
  `ConclusionScopeAio.query`, merged over the scope's observer/observed.
- TypeScript: add optional `filters` arg to `ConclusionScope.query`,
  mirroring the existing `list()` change.

The server `/conclusions/query` endpoint already honors filters in the body
(verified against production), so this is purely SDK surface parity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The using-filters page covered workspaces/peers/sessions/messages but not
conclusions. Add a "Filtering Conclusions" section showing level-based
filtering on both list() and query(), including the common "explicit only"
(exclude dream-derived) case and the in[deductive,inductive] inverse.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3208b95e-2357-4027-9217-3cfd977b3223

📥 Commits

Reviewing files that changed from the base of the PR and between eb0202b and d0aff04.

📒 Files selected for processing (5)
  • sdks/python/src/honcho/aio.py
  • sdks/python/src/honcho/conclusions.py
  • sdks/typescript/__tests__/conclusions.test.ts
  • sdks/typescript/src/conclusions.ts
  • tests/sdk/test_conclusions.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • sdks/python/src/honcho/aio.py
  • sdks/python/src/honcho/conclusions.py
  • sdks/typescript/src/conclusions.ts

Walkthrough

Conclusion responses now include a typed level field across backend schema and Python/TypeScript SDK models. Conclusion list/query calls in both SDKs accept optional filters with reserved-key validation, and the docs plus route tests cover level-based filtering.

Changes

Conclusion levels and scoped filters

Layer / File(s) Summary
API contract
src/schemas/api.py, sdks/python/src/honcho/api_types.py, sdks/typescript/src/types/api.ts, sdks/typescript/src/index.ts
Adds the level field and allowed level values to conclusion response schemas and API types, and re-exports the new TypeScript type.
Python SDK
sdks/python/src/honcho/conclusions.py, sdks/python/src/honcho/aio.py, tests/sdk/test_conclusions.py
Adds level to Python conclusion models and makes conclusion list/query calls merge caller filters with scope/session identifiers after rejecting reserved keys.
TypeScript SDK
sdks/typescript/src/conclusions.ts, sdks/typescript/__tests__/conclusions.test.ts
Adds level to TypeScript conclusion models and makes conclusion list/query calls merge caller filters with scope/session identifiers after rejecting reserved keys.
Docs and route coverage
docs/v3/documentation/features/advanced/using-filters.mdx, tests/routes/test_conclusions.py
Adds conclusion-level filter examples to the guide and updates route tests to assert level mapping and level-based filtering.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • VVoruganti

Poem

(_/)
(•ㅅ•) I hopped through filters, level by level,
carrots of explicit and deductive did revel.
Python, TypeScript, and docs got a tidy little thump,
now this bunny says: “conclusions go bump!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the main change by describing the new conclusions level filter.
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch abigail/conclusions-level-filter

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
sdks/python/src/honcho/conclusions.py (1)

202-209: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Caller filters can silently override scope keys.

merged_filters.update(filters) applies caller-provided filters last, so a caller passing observer_id/observed_id/session_id inside filters will overwrite the scope-injected values rather than supplementing them. This mirrors the TypeScript SDK, so it may be intentional, but if scope identity should be authoritative consider seeding caller filters first and re-applying scope keys afterward.

♻️ Optional: make scope keys authoritative
-        merged_filters: dict[str, Any] = {
-            "observer_id": self.observer,
-            "observed_id": self.observed,
-        }
-        if resolved_session_id:
-            merged_filters["session_id"] = resolved_session_id
-        if filters:
-            merged_filters.update(filters)
+        merged_filters: dict[str, Any] = dict(filters) if filters else {}
+        merged_filters["observer_id"] = self.observer
+        merged_filters["observed_id"] = self.observed
+        if resolved_session_id:
+            merged_filters["session_id"] = resolved_session_id
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/python/src/honcho/conclusions.py` around lines 202 - 209, The merged
filter construction in `Conclusions` currently lets caller-supplied `filters`
override scope identity keys like `observer_id`, `observed_id`, and
`session_id`. If scope keys should be authoritative, change the merge order in
the method building `merged_filters` so caller filters are applied first and
then re-apply the scope values afterward, ensuring `self.observer`,
`self.observed`, and the resolved session id cannot be overwritten.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@sdks/python/src/honcho/conclusions.py`:
- Around line 202-209: The merged filter construction in `Conclusions` currently
lets caller-supplied `filters` override scope identity keys like `observer_id`,
`observed_id`, and `session_id`. If scope keys should be authoritative, change
the merge order in the method building `merged_filters` so caller filters are
applied first and then re-apply the scope values afterward, ensuring
`self.observer`, `self.observed`, and the resolved session id cannot be
overwritten.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ed5ed6ea-df1b-45ca-b4a0-8be5485e7bb9

📥 Commits

Reviewing files that changed from the base of the PR and between eb386c3 and 14c9f90.

📒 Files selected for processing (9)
  • docs/v3/documentation/features/advanced/using-filters.mdx
  • sdks/python/src/honcho/aio.py
  • sdks/python/src/honcho/api_types.py
  • sdks/python/src/honcho/conclusions.py
  • sdks/typescript/src/conclusions.ts
  • sdks/typescript/src/index.ts
  • sdks/typescript/src/types/api.ts
  • src/schemas/api.py
  • tests/routes/test_conclusions.py

Replace the merged_filters + if-block pattern in list()/query() (py sync,
aio, ts) with a single dict spread that layers the caller's filters over the
scope's observer/observed (and session). No behavior change — same merge
order (caller wins) — just less code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mintlify

mintlify Bot commented Jun 26, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
plasticlabs 🟢 Ready View Preview Jun 26, 2026, 9:22 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

The generic filters= argument on ConclusionScope.list()/query() spread
user-supplied filters last, so a stray observer/observed/session key
silently overrode the scope and returned data from a different peer
pair. Add a fail-loud guard in both the Python and TypeScript SDKs that
rejects scope-managed filter keys with a clear error, directing callers
to peer.conclusions / conclusions_of(target) and the session= parameter.
session_id remains a valid filter on query() (which has no dedicated
session parameter).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants