anhtld commited on
Commit
a22955d
·
verified ·
1 Parent(s): 2f6efaf

sync chart feature code 2026-07-03

Browse files
Files changed (1) hide show
  1. workspace/cil/chart_features.py +56 -0
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)]