feat(explore): sporet sier HVILKE dokumenter navigatoeren aapnet, ikke bare hvilken base

S7a-3 pkt. 3. ExplorationToolRecorder registrerte navn + bundle_id i
kall-rekkefoelge. Over 39 konsepter holdt det; over K2s 629 leser tool_calls
"read_file, k2" to ganger, saa hvilke to av 629 kan ikke leses ut av den
leverte artefakten i det hele tatt - oekt 77 og 81 maatte begge instrumentere
kjoeringen for haand for aa svare.

ToolCall.path registreres for read_file OG read_dir. Resultatet registreres
fortsatt ALDRI: det ER basens innhold, maalt til 89 % av hver prompt-token i en
K2-kjoering. "" for et verktoey som ikke tar argumentet (bundle_id-regelen), og
EN argumentleser for begge felt - to kopier ville staatt fritt til aa vaere
uenige om hva et fravaerende argument betyr.

Load-bearing MAALT: 4 mutasjoner alle roede mot HELE suiten, groenn kontroll
1257 passed / 5 skipped, golden byte-uendret. P1 3 / P2 3 / P3 2 / P4 2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-03 08:03:36 +02:00
commit f17068b013
4 changed files with 224 additions and 14 deletions

View file

@ -268,29 +268,40 @@ class QuickValidation:
class ToolCall:
"""One exploration tool invocation: what was asked for, never what came back.
``bundle_id`` is the base the call named, and is ``""`` for a tool that takes none
(``list_bundles``). The RESULT is deliberately absent: it is the base's content, which is the
``bundle_id`` is the base the call named, and ``path`` the document or directory inside it
each ``""`` for a tool that does not take it (``list_bundles`` takes neither, ``read_bundle``
takes only the base). The RESULT is deliberately absent: it is the base's content, which is the
very thing that is too big to ride along (MAJOR-3 measured it at 73-93 % of all prompt tokens),
and a trace carrying it would be a second copy of the context rather than a record of the run.
``path`` was added in S7a-3 pkt. 3, and the measurement that forced it is scale: over the three
example bases the name and the base id were enough to see what a run had done, but over K2's
**629 concepts** a trace reading ``read_file, k2`` twice answers nothing about WHICH two were
opened. It is recorded for ``read_file`` and for ``read_dir`` a trace that named the documents
but not the directories would say where a run ended without saying how it got there.
"""
name: str
bundle_id: str
path: str
def _bundle_argument(arguments: Any) -> str:
"""The ``bundle_id`` a call named, from either shape ``FunctionInvocationContext`` allows.
def _string_argument(arguments: Any, key: str) -> str:
"""One named argument of a call, from either shape ``FunctionInvocationContext`` allows.
``arguments`` is typed ``BaseModel | Mapping[str, Any]`` (measured against the installed
signature), so both are read rather than one being assumed. A tool without the parameter or
a value that is not a string yields ``""``: the recorder describes the call, and inventing a
label for a base that was never named would be the false-attribution that ``ToolCallRecorder``
refuses for unconfigured tools.
value for an argument that was never passed would be the false-attribution that
``ToolCallRecorder`` refuses for unconfigured tools.
ONE reader for both fields (-(p)): two copies of "read this key out of either shape" would be
free to disagree about what an absent argument means.
"""
if isinstance(arguments, Mapping):
value: Any = arguments.get("bundle_id")
value: Any = arguments.get(key)
else:
value = getattr(arguments, "bundle_id", None)
value = getattr(arguments, key, None)
return value if isinstance(value, str) else ""
@ -319,8 +330,13 @@ class ExplorationToolRecorder(FunctionMiddleware):
) -> None:
name = getattr(getattr(context, "function", None), "name", None)
if isinstance(name, str):
arguments = getattr(context, "arguments", None)
self._sink.append(
ToolCall(name=name, bundle_id=_bundle_argument(getattr(context, "arguments", None)))
ToolCall(
name=name,
bundle_id=_string_argument(arguments, "bundle_id"),
path=_string_argument(arguments, "path"),
)
)
await call_next()
@ -404,7 +420,8 @@ def trace_payload(trace: ExplorationTrace, *, stop: str | None, completed: bool)
for call in trace.quick_validations
],
"tool_calls": [
{"name": call.name, "bundle_id": call.bundle_id} for call in trace.tool_calls
{"name": call.name, "bundle_id": call.bundle_id, "path": call.path}
for call in trace.tool_calls
],
}