Repository navigation
feat(repo): process metrics in result.json, manifest process_metrics, grade optional for dokimi: graders #157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
napetrov
wants to merge
13
commits into
intel:main
Choose a base branch
from
napetrov:d4-process-metrics
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+521
−10
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
343f7ac
feat(repo): process metrics in result.json, manifest process_metrics,…
napetrov d9c92f4
Merge remote-tracking branch 'intel/main' into sweep1022-157
napetrov 3c8a0cc
test(repo): pin process-metrics wiring in repo run and a dokimi:-only…
napetrov 24a292f
fix(repo): refuse a repository grader without entry_points.grade befo…
xaleryb a296a67
fix(repo): refuse a process_metrics name that is not a string
xaleryb 732cb6b
fix(repo): do not count a permission-denied command as failed
xaleryb 56fe503
fix(repo): count only workspace guidance files the agent read in guid…
xaleryb 406d986
Use BUILTIN_PREFIX from graders in grade_problems
antonwolfy 81e80b4
State that a process_metrics name cannot start with a digit
antonwolfy 0fbf76c
Say entry_points.grade is optional for dokimi: graders in section 4.5
antonwolfy f587046
Merge intel/main into d4-process-metrics
napetrov f9b314c
fix(repos): guidance_read skips failed reads and normalizes paths; pi…
napetrov 135a5ed
fix(repos): process is null for an agent that left no trace
napetrov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
dokimi/changelog.d/20261021_140000_napetrov_d4-process-metrics.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| ### Added | ||
|
|
||
| - **Process metrics in `result.json`** — every `repo run` cell's `result.json` has a | ||
| `process` object counted from `events.jsonl`: `tool_calls`, `commands`, | ||
| `failed_commands` (not denied, `rc` neither 0 nor null), `denied_commands`, and `guidance_read` (the | ||
| workspace paths read, not denied, that the manifest's guidance globs match). A manifest's new `process_metrics:` maps | ||
| a name to a regex, searched in each command's text, or its `output` (`match: output|any`), | ||
| and `process.counters` holds each count. `repo validate` refuses a regex that does not | ||
| compile, and a name that is not a string (a bare YAML `404:` or `on:`). | ||
|
|
||
| ### Changed | ||
|
|
||
| - **`entry_points.grade` is optional** when every task's grader is a built-in `dokimi:` one; | ||
| `repo validate`, `repo run` and `repo tasks check` name the tasks that need it otherwise, | ||
| the last two before any agent runs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| # Copyright (C) 2026 Intel Corporation | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| """Process metrics of one run, from its ``events.jsonl`` events, for ``result.json`` ``process`` (contract §4.1). | ||
|
|
||
| The framework counts what every repository asks of a trace: | ||
|
|
||
| - ``tool_calls``: every event, so every tool call of the parent and its subagents; | ||
| - ``commands``: the ``command`` events; | ||
| - ``failed_commands``: commands not denied whose ``rc`` is neither ``0`` nor ``null`` (``null`` means | ||
| no result came back, which is not a failure; a permission denial carries ``rc`` 1 but never ran); | ||
| - ``denied_commands``: commands a hook or the harness's permissions refused (``denied``); | ||
| - ``guidance_read``: the sorted workspace paths of ``read`` events not denied that the manifest's guidance | ||
| globs match; a path outside the workspace (absolute, or with ``..``) is no repository file. | ||
|
|
||
| ``counters`` holds the manifest's ``process_metrics``: for each name, how many ``command`` events | ||
| its regex finds a match in (``re.search``). A counter matches the command text unless it names | ||
| ``output`` (the command's output, as clipped in the event) or ``any`` (either). | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import posixpath | ||
| import re | ||
| from collections.abc import Callable, Iterable, Mapping | ||
| from dataclasses import dataclass | ||
| from pathlib import PurePosixPath | ||
| from typing import Any | ||
|
|
||
| COUNTER_FIELDS = ("text", "output", "any") | ||
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class Counter: | ||
| """One ``process_metrics`` entry: a compiled regex and the command field it searches.""" | ||
|
|
||
| pattern: re.Pattern[str] | ||
| field: str = "text" | ||
|
|
||
| def hits(self, event: Mapping[str, Any]) -> bool: | ||
| fields = ("text", "output") if self.field == "any" else (self.field,) | ||
| return any(self.pattern.search(str(event.get(f) or "")) for f in fields) | ||
|
|
||
|
|
||
| def parse_counter(name: str, value: Any) -> Counter: | ||
| """A ``process_metrics`` value, ``<regex>`` or ``{regex: <regex>, match: text|output|any}``. | ||
|
|
||
| Raises ``ValueError`` naming the metric when the regex does not compile or the shape is wrong.""" | ||
| regex, where = (value, "text") if isinstance(value, str) else ( | ||
| (value.get("regex"), value.get("match", "text")) if isinstance(value, dict) else (None, None)) | ||
| if not isinstance(regex, str) or not regex: | ||
| raise ValueError(f"process_metrics/{name}: give a regex, or {{regex: <regex>, match: text|output|any}}") | ||
| if where not in COUNTER_FIELDS: | ||
| raise ValueError(f"process_metrics/{name}: match must be one of {', '.join(COUNTER_FIELDS)}, got {where!r}") | ||
| try: | ||
| return Counter(re.compile(regex), where) | ||
| except re.error as exc: | ||
| raise ValueError(f"process_metrics/{name}: not a valid regex: {exc}") from exc | ||
|
|
||
|
|
||
| def _workspace_path(path: str) -> str | None: | ||
| """``path`` normalized (``./a``, ``a//b``, ``a/./b``), or None when it is not inside the workspace. | ||
|
|
||
| A ``..`` that stays inside (``src/../AGENTS.md``) is resolved; ``~`` is a home directory, not the repository.""" | ||
| if path.startswith("~"): | ||
| return None | ||
| p = PurePosixPath(posixpath.normpath(path)) | ||
| if p.is_absolute() or ".." in p.parts: | ||
| return None | ||
| return str(p) | ||
|
|
||
|
|
||
| def process_metrics(events: Iterable[Mapping[str, Any]], is_guidance: Callable[[str], bool], | ||
| counters: Mapping[str, Counter] | None = None) -> dict[str, Any]: | ||
| """The ``process`` object of ``result.json`` for one run's events; ``is_guidance`` tells a guidance path.""" | ||
| events = list(events) | ||
| commands = [e for e in events if e.get("kind") == "command"] | ||
| # A read that failed (rc 1: the file does not exist) read no guidance. | ||
| reads = {w for e in events if e.get("kind") == "read" and e.get("path") and not e.get("denied") | ||
| and e.get("rc") in (0, None) and (w := _workspace_path(str(e["path"]))) is not None} | ||
| return { | ||
| "tool_calls": len(events), | ||
| "commands": len(commands), | ||
| "failed_commands": sum(e.get("rc") not in (0, None) and not e.get("denied") for e in commands), | ||
| "denied_commands": sum(bool(e.get("denied")) for e in commands), | ||
| "guidance_read": sorted(p for p in reads if is_guidance(p)), | ||
| "counters": {name: sum(c.hits(e) for e in commands) for name, c in (counters or {}).items()}, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.