Skip to content

feat(kb): type ask/post results via binding_model keyword - #62

Merged
david-debest merged 1 commit into
mainfrom
57-feat/typed-ask-post-results
Oct 1, 2026
Merged

david-debest merged 1 commit into
mainfrom
57-feat/typed-ask-post-results

Conversation

@david-debest

@david-debest david-debest commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Closes #57

Problem

kb.ask() / kb.ask_with_info() (and the POST equivalents) are typed as returning Sequence[BindingModel] | BindingSet, even when the KI was registered with a binding model. At runtime the results are already validated into that model, but the type checker can't know it: the KI is looked up by a ki_name string. Callers had to use cast() or # type: ignore.

Solution

All outgoing methods (ask, ask_with_info, post, post_with_info and their *_sync bridges) take a keyword-only argument that types the result:

people = await kb.ask(bs, "ask-ki", binding_model=PersonBinding)                  # Sequence[PersonBinding]
res = await kb.post_with_info(bs, "post-ki", result_binding_model=ResultBinding)  # ExchangeResult[ResultBinding]
  • binding_model (ASK) / result_binding_model (POST) mirror the parameter names of ask_ki() / post_ki().
  • The argument only sets the result type: parsing still uses the model registered for the KI. Passing a different model (including one for a KI registered without a model) raises ValueError, so the static type can't lie.
  • Uses PEP 696 TypeVar defaults (Python 3.13+), so each method has a single signature and no overloads.
  • ExchangeResult is now generic in its binding type.
  • Examples 03, 04 and 07 pass the model (07 drops its # type: ignore workarounds); README and CONTEXT.md are updated.

Behaviour change (typing only)

Without the keyword, the result type is now Sequence[BindingModel | dict[str, str]] instead of Sequence[BindingModel] | Sequence[dict[str, str]]. Runtime behaviour is unchanged, but code that annotated a variable with the old union may get a new type-checker error.

Verification

  • New tests: typed results for ask/post, ValueError on a mismatching model (async and sync bridges).
  • Checked inference with both pyright and mypy: Sequence[P] / ExchangeResult[Q] with a model, the union without one.

Notes

Results of kb.ask()/kb.post() were typed as Sequence[BindingModel] | BindingSet
even when the KI has a binding model, forcing callers to cast(). The outgoing
methods (incl. *_with_info and *_sync) now take a keyword-only binding_model
(ASK) / result_binding_model (POST) that types the result; parsing still uses
the registered model and a mismatch raises ValueError. ExchangeResult is
generic in its binding type.

Closes #57

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@david-debest
david-debest force-pushed the 57-feat/typed-ask-post-results branch from 628e0fb to 35bcf40 Compare October 1, 2026 12:02
@david-debest david-debest changed the title feat(kb): return typed AskKI/PostKI handles from ask_ki/post_ki feat(kb): type ask/post results via binding_model keyword Oct 1, 2026
@david-debest
david-debest merged commit 9991920 into main Oct 1, 2026
3 checks passed
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.

Support setting return type of kb.ask() with generics: kb.ask[ReturnBinding]()

1 participant