feat: normailze intinsics interfaces#1028
feat: normailze intinsics interfaces#1028akihikokuroda wants to merge 3 commits intogenerative-computing:mainfrom
Conversation
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
|
The PR description has been updated. Please fill out the template for your PR to be reviewed. |
planetf1
left a comment
There was a problem hiding this comment.
threading looks good, and catching the float → str return type mismatch was worth doing. Two things I'd want resolved before merging: the from_context tests won't actually exercise the code path they're meant to cover, and the documents positional change breaks existing callers without any mention in the issue or PR. The latter is easy to fix without the break — see inline.
| # Add documents to the last assistant message | ||
| last_turn = context.last_turn() | ||
| assert last_turn is not None and last_turn.output is not None | ||
| assert last_turn.output.value is not None |
There was a problem hiding this comment.
These assertions will never pass as written. _read_guardian_input builds context via context.add(Message(...)), which means the last node is a Message, not a ModelOutputThunk — so last_turn() returns ContextTurn(last_element, None) (base.py:919). .output is always None here. The test aborts before reaching the code it's supposed to cover, so the documents=None branch in factuality_detection is entirely uncovered.
The fix is to use the same extraction path that guardian.py itself falls back to:
last_turn = context.last_turn()
assert last_turn is not None
if last_turn.output is not None and last_turn.output.value is not None:
content = last_turn.output.value
else:
assert isinstance(last_turn.model_input, Message)
content = last_turn.model_input.content
rewound = context.previous_node
assert rewound is not None
context_with_docs: ChatContext = rewound.add( # type: ignore[assignment]
Message("assistant", content, documents=documents)
)Same issue at lines 220–221 in test_factuality_correction_from_context.
| def factuality_detection(context: ChatContext, backend: AdapterMixin) -> float: | ||
| """Determine is the last response is factually incorrect. | ||
| def factuality_detection( | ||
| documents: collections.abc.Iterable[str | Document] | None, |
There was a problem hiding this comment.
Making documents the new first positional arg is a silent break — existing callers doing factuality_detection(ctx, backend) now pass ctx as documents and get a confusing error rather than a helpful one. Neither #1003 nor this PR mentions it as a breaking change, and our policy is to avoid that without explicit callout.
The good news is the issue just asks for parity with the other intrinsics — we can get there without the break by making documents keyword-only:
def factuality_detection(
context: ChatContext,
backend: AdapterMixin,
*,
documents: collections.abc.Iterable[str | Document] | None = None,
model_options: dict | None = None,
) -> str:Existing call sites continue to work, new callers pass documents= explicitly, and it's consistent with how model_options is handled everywhere else in this PR. Worth also updating the AGENTS.md Section 13 table with the new signature.
|
|
||
| # If documents are provided, add them to the last assistant message | ||
| if documents is not None: | ||
| # Get the last turn and add documents to it |
There was a problem hiding this comment.
This block extracting the assistant content, rewinding the context, and reattaching documents is identical in factuality_correction (~lines 303–336). If either of the fixes above lands here, it'll need to land in both places. Would be cleaner to pull it into a private helper — something like _reattach_documents(context, documents) -> ChatContext — which also gives us one place to sort out the cast() vs type: ignore question below.
|
|
||
| # Extract assistant content from either output (if generated) or model_input (if manually added) | ||
| if last_turn.output is not None and last_turn.output.value is not None: | ||
| assistant_content = last_turn.output.value |
There was a problem hiding this comment.
Small edge case: if last_turn.output is not None but .value is None (uncomputed thunk, failed generation), the code falls through to model_input and ends up wrapping the user's question as the assistant's response. That'll produce a factuality score on the wrong text with no indication anything went wrong. Raising explicitly there rather than falling through would be much easier to debug.
| raise ValueError("Cannot rewind context past the root node") | ||
| # Type ignore because rewound is Context but we know it's ChatContext | ||
| context = rewound.add( # type: ignore[assignment] | ||
| Message( |
There was a problem hiding this comment.
# type: ignore[assignment] is hiding a real mismatch: previous_node.add(...) returns Context, not ChatContext. Worth using cast(ChatContext, rewound.add(...)) with a short note explaining why, rather than silencing mypy here — if the type hierarchy shifts this will fail at runtime instead of at type-check time. As above, extracting the helper means one fix instead of two.
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
Misc PR
Type of PR
Description
Testing
Attribution