sync chart feature code 2026-07-03
Browse files
workspace/cil/chart_features.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
from typing import Any
|
| 5 |
+
|
| 6 |
+
try:
|
| 7 |
+
import numpy as np
|
| 8 |
+
except ImportError: # pragma: no cover
|
| 9 |
+
np = None
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
CONTEXT_HASH_WIDTH = 8
|
| 13 |
+
CHART_FEATURE_MODES = ("base", "base_context")
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def build_chart_feature(
|
| 17 |
+
base_action: Any,
|
| 18 |
+
metadata: dict[str, Any] | None = None,
|
| 19 |
+
*,
|
| 20 |
+
mode: str = "base",
|
| 21 |
+
) -> Any:
|
| 22 |
+
"""Build a deployment-visible chart feature vector.
|
| 23 |
+
|
| 24 |
+
`base` preserves the original behavior: the chart token is the flattened
|
| 25 |
+
base action chunk. `base_context` appends stable hashes of task/language
|
| 26 |
+
metadata that are visible at proposal time. It intentionally does not read
|
| 27 |
+
outcomes, labels, hidden chart branches, or evaluator-only fields.
|
| 28 |
+
"""
|
| 29 |
+
|
| 30 |
+
if np is None: # pragma: no cover
|
| 31 |
+
raise ImportError("build_chart_feature requires numpy")
|
| 32 |
+
if mode not in CHART_FEATURE_MODES:
|
| 33 |
+
raise ValueError(f"unknown chart feature mode: {mode}")
|
| 34 |
+
base = np.asarray(base_action, dtype=np.float32).reshape(-1)
|
| 35 |
+
if mode == "base":
|
| 36 |
+
return base
|
| 37 |
+
metadata = metadata or {}
|
| 38 |
+
context = np.asarray(
|
| 39 |
+
[
|
| 40 |
+
*_stable_hash_features(str(metadata.get("task_id", "")), CONTEXT_HASH_WIDTH),
|
| 41 |
+
*_stable_hash_features(str(metadata.get("instruction", "")).lower(), CONTEXT_HASH_WIDTH),
|
| 42 |
+
min(len(str(metadata.get("instruction", ""))) / 128.0, 4.0),
|
| 43 |
+
min(len(str(metadata.get("instruction", "")).split()) / 32.0, 4.0),
|
| 44 |
+
],
|
| 45 |
+
dtype=np.float32,
|
| 46 |
+
)
|
| 47 |
+
return np.concatenate([base, context]).astype(np.float32, copy=False)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def chart_feature_dim(base_action: Any, *, mode: str = "base") -> int:
|
| 51 |
+
return int(build_chart_feature(base_action, {}, mode=mode).reshape(-1).shape[0])
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def _stable_hash_features(text: str, width: int) -> list[float]:
|
| 55 |
+
digest = hashlib.sha256(text.encode("utf-8")).digest()
|
| 56 |
+
return [float(digest[index] / 127.5 - 1.0) for index in range(width)]
|