The call record: every model call, for the operator's study (M6.6a)
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m54s
CI / e2e (pull_request) Successful in 4m20s

nisse-core records each model call of every agent into a file beside its
state store (<state>.calls.db), for the status page (L7, X6):

- the request body exactly as sent (never headers), the raw response with
  its reasoning, the model asked and the one that answered, time, tokens
  and llama-server's own prompt reuse (timings.cache_n);
- its work item, role, run and purpose: Driver.run and nisse-dev's
  delegation loop open runs, nested; compaction, expert consults, the
  classifier and the go-ahead reader label their calls;
- provenance, worked out in BudgetedClient by comparing the events at
  each stage: each event sent with its log id and content as sent, which
  a compaction replaced, which fitting shortened (by how much) and
  dropped.

Content is stored once by hash, compressed. It is diagnostic only: the
agent never reads it, a failed write is logged once and recording stops
while the call goes on, and the file is deleted when the agent starts,
so its layout never migrates; CallReader refuses a layout it doesn't
know. While recording, the system prompt ends with one sentence saying
so. `call_record: false` in either agent's YAML turns it off.

The benchmark records each run beside that run's own state store, and
`--keep-runs DIR` keeps both for the page.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
dongarandClaude Opus 5.5 committed 2026-10-24 06:28:53 +00:00
1 parent cba35eb7d4
commit dd060566b2
22 files changed
+1346 -48

No files matched your search

+2
View File
@@ -9,6 +9,7 @@ from nisse_core.knowledge.memory import Memory
from nisse_core.knowledge.vault import Vault
from nisse_core.loop.driver import Driver
from nisse_core.loop.expert import ExpertDesk
from nisse_core.models import calls
from nisse_core.models.catalog import ModelCatalog
from nisse_core.models.compact import Compactor
from nisse_core.models.context import BudgetedClient
@@ -94,6 +95,7 @@ def llm_client(config: ReviewConfig, oplog: OpLog | None = None) -> BudgetedClie
safety_margin=tuning.safety_margin,
enforces_tool_choice=lambda m: catalog.facts(m).supports_tool_choice is True,
oplog=oplog, # a cut that fitting has to make is logged
call_recorder=calls.recorder_for(config.state_db, config.call_record, oplog),
)
+7
View File
@@ -47,6 +47,8 @@ OPTIONAL_KEYS = (
# Patterns of the repositories it reviews ("dev/nisse", "dev/*", "*/*"),
# public ones included; unset, every one it was given (R1, ``access``).
"repositories",
# Record every model call for the operator's study (L7); on unless false.
"call_record",
)
@@ -108,6 +110,7 @@ class ReviewConfig:
gitea_operators: frozenset[str] # whose comments are the operator's (R4)
max_output_tokens: int = DEFAULT_MAX_OUTPUT_TOKENS
request_timeout_s: float = DEFAULT_REQUEST_TIMEOUT_S
call_record: bool = True # every model call recorded for the operator (L7)
tuning: Tuning = field(default_factory=Tuning)
vault: VaultConfig | None = None
repositories: frozenset[str] | None = None # None: all it can read
@@ -158,6 +161,9 @@ class ReviewConfig:
owner, slash, name = pattern.partition("/")
if not (owner and slash and name) or "/" in name:
errors.append(f"repositories: {pattern!r} is not owner/name")
record = values.get("call_record", True)
if not isinstance(record, bool):
errors.append("call_record: true or false")
if errors:
raise ConfigError("cannot start: " + "; ".join(errors))
reviewer = str(values["roles.reviewer"])
@@ -173,6 +179,7 @@ class ReviewConfig:
gitea_operators=people(values["gitea.operators"]),
max_output_tokens=max_output,
request_timeout_s=timeout,
call_record=record,
tuning=tuning,
vault=vault,
repositories=patterns,