TheRealAIGuy commited on
Commit
56acd24
Β·
1 Parent(s): ee1bcdc

Tasks & Inference modih-fied

Browse files
inference.py CHANGED
@@ -1,5 +1,12 @@
1
  #!/usr/bin/env python3
2
 
 
 
 
 
 
 
 
3
  import os
4
  import sys
5
  import json
@@ -7,7 +14,8 @@ import re
7
  import datetime
8
  import traceback
9
  import time
10
- from typing import List
 
11
 
12
  from dotenv import load_dotenv
13
  load_dotenv()
@@ -18,7 +26,7 @@ if _ROOT not in sys.path:
18
  sys.path.insert(0, _ROOT)
19
 
20
  from openai import OpenAI
21
- from pydantic import BaseModel, ValidationError
22
 
23
  try:
24
  from hft_auditor_env import FinAuditorEnv as FinAuditorEnvironment
@@ -31,14 +39,15 @@ class LLMResponse(BaseModel):
31
  reasoning: str
32
  decisions: List[int]
33
 
34
- API_BASE_URL: str = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
35
- MODEL_NAME: str = os.getenv("MODEL_NAME", "meta-llama/Meta-Llama-3-8B-Instruct")
36
- HF_TOKEN: str = os.getenv("HF_TOKEN")
37
 
38
  if not HF_TOKEN:
39
- raise ValueError("CRITICAL: HF_TOKEN environment variable is missing.")
40
 
41
  TASK_ID: str = os.getenv("TASK_ID", "anomaly_detection_hard")
 
42
 
43
  if "easy" in TASK_ID.lower():
44
  _DEFAULT_MAX = 5
@@ -48,31 +57,48 @@ else:
48
  _DEFAULT_MAX = 20
49
 
50
  MAX_STEPS: int = int(os.getenv("MAX_STEPS", str(_DEFAULT_MAX)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- _client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
53
-
54
- SYSTEM_PROMPT = """\
55
- You are a Wall Street Compliance Auditor AI embedded inside a High-Frequency Trading audit engine.
56
- You MUST think step-by-step in the 'reasoning' field before determining your action.
57
-
58
- ━━━ DECISION VALUES ━━━
59
- You must output ONLY raw integers (0 or 1) in the array. NO strings. NO labels.
60
- 1 : Confirmed anomaly.
61
- 0 : Trade is clean.
62
 
63
- ━━━ EVALUATION DIRECTIVE ━━━
64
- 1. CRITICAL SIGNAL (FLAG): If risk_score > 0.60, output 1.
65
- 2. NOISE SIGNAL (PASS): If risk_score < 0.30, output 0.
66
- 3. AMBIGUITY (FLAG): If risk_score is in between, output 1 to be safe.
67
 
68
- ━━━ CRITICAL JSON FORMAT ━━━
69
- You MUST respond with a valid JSON object. The decisions array MUST contain exactly the requested number of raw integers. NO trailing commas.
70
- Example:
71
- {"reasoning": "Trade 1 has high risk. Trade 2 is safe.", "decisions": [1, 0, 1]}
72
- """
 
 
73
 
74
- def _ts() -> str:
75
- return datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
 
76
 
77
  def _build_user_prompt(step: int, features: list[list[float]]) -> str:
78
  lines = [
@@ -90,8 +116,6 @@ def _build_user_prompt(step: int, features: list[list[float]]) -> str:
90
  lines.append(f"Provide exactly {len(features)} decisions as a JSON object.")
91
  return "\n".join(lines)
92
 
93
- _last_reasoning: str = ""
94
-
95
  def _parse_llm_decisions(content: str, expected_count: int) -> list[int]:
96
  global _last_reasoning
97
  stripped = content.strip()
@@ -133,7 +157,7 @@ def _normalize_decisions(decisions: list[int], expected: int) -> list[int]:
133
  clamped.append(1)
134
  return clamped
135
 
136
- def _call_llm(step: int, features: list[list[float]]) -> list[int]:
137
  global _last_reasoning
138
  _last_reasoning = "Fallback triggered."
139
  user_prompt = _build_user_prompt(step, features)
@@ -141,24 +165,25 @@ def _call_llm(step: int, features: list[list[float]]) -> list[int]:
141
 
142
  for attempt in range(max_retries):
143
  try:
144
- response = _client.chat.completions.create(
145
  model=MODEL_NAME,
146
  messages=[
147
  {"role": "system", "content": SYSTEM_PROMPT},
148
  {"role": "user", "content": user_prompt},
149
  ],
150
- max_tokens=1500,
151
- temperature=0.0,
 
152
  )
153
- content = response.choices[0].message.content or ""
154
  return _parse_llm_decisions(content, len(features))
155
- except Exception as e:
 
156
  time.sleep(1)
157
 
158
  fallback_decisions = []
159
  for row in features:
160
  if len(row) >= 4:
161
- # Matches SYSTEM_PROMPT: 1 if > 0.60, 0 if < 0.30, 1 if in between.
162
  risk_score = row[3]
163
  fallback_decisions.append(0 if risk_score < 0.30 else 1)
164
  else:
@@ -166,19 +191,20 @@ def _call_llm(step: int, features: list[list[float]]) -> list[int]:
166
 
167
  return fallback_decisions
168
 
169
- def run_inference() -> None:
170
- # 1. Initialize all tracking variables for the safety net
171
- steps_completed: int = 0
172
- all_rewards: list[float] = []
173
- success: bool = False
 
 
174
 
175
- # 2. Emitting [START] strictly in plain text (NO JSON)
176
- print(f"[START] task={TASK_ID} env=fin_auditor model={MODEL_NAME}", flush=True)
177
 
 
178
  try:
179
  env = FinAuditorEnvironment()
180
 
181
- # Determine the correct task configuration dynamically based on TASK_ID
182
  if "easy" in TASK_ID.lower():
183
  from tasks.task1_easy import setup_env
184
  setup_env(env)
@@ -191,49 +217,54 @@ def run_inference() -> None:
191
 
192
  obs = env.reset()
193
 
194
- for step_num in range(1, MAX_STEPS + 1):
195
- step_reward = 0.0
196
  features = obs.features
197
 
198
  if not features:
 
199
  action = AuditorAction(decisions=[])
200
  global _last_reasoning
201
  _last_reasoning = "Empty matrix."
202
  else:
203
- decisions = _call_llm(step_num, features)
204
  action = AuditorAction(decisions=decisions)
205
 
206
  obs = env.step(action)
207
- step_reward = float(obs.reward) if obs.reward is not None else 0.1
208
- all_rewards.append(step_reward)
209
- steps_completed = step_num
 
210
 
211
- # 3. Emitting [STEP] strictly in plain text (NO JSON)
212
- action_str = ",".join(str(d) for d in action.decisions) if action.decisions else "none"
213
- done_str = "true" if obs.done else "false"
214
 
215
- print(f"[STEP] step={step_num} action={action_str} reward={step_reward:.2f} done={done_str} error=null", flush=True)
 
216
 
217
- if obs.done:
218
  break
219
 
220
- # If we made it out of the loop without crashing, we succeeded
221
- success = True
 
 
222
 
223
- except KeyboardInterrupt:
224
- print("[SYS] Interrupted by user.", file=sys.stderr, flush=True)
225
  except Exception as exc:
 
226
  traceback.print_exc(file=sys.stderr)
227
  finally:
228
-
229
- # Get the final step's reward as the overall score
230
- raw_score = all_rewards[-1] if all_rewards else 0.1
231
-
232
- # Clamp it exactly as the Discord instructions require
233
- final_score = max(0.01, min(0.99, float(raw_score)))
 
 
 
 
234
 
235
- # Emit the EXACT string format the evaluator is searching for
236
- print(f"[END] task={TASK_ID} score={final_score:.2f} steps={steps_completed}", flush=True)
237
 
238
  if __name__ == "__main__":
239
- run_inference()
 
1
  #!/usr/bin/env python3
2
 
3
+ """
4
+ Inference Script for FinAuditor
5
+ ===================================
6
+ Refactored to strictly match the STDOUT FORMAT template.
7
+ """
8
+
9
+ import asyncio
10
  import os
11
  import sys
12
  import json
 
14
  import datetime
15
  import traceback
16
  import time
17
+ import textwrap
18
+ from typing import List, Optional
19
 
20
  from dotenv import load_dotenv
21
  load_dotenv()
 
26
  sys.path.insert(0, _ROOT)
27
 
28
  from openai import OpenAI
29
+ from pydantic import BaseModel
30
 
31
  try:
32
  from hft_auditor_env import FinAuditorEnv as FinAuditorEnvironment
 
39
  reasoning: str
40
  decisions: List[int]
41
 
42
+ API_BASE_URL: str = os.getenv("API_BASE_URL") or "https://router.huggingface.co/v1"
43
+ MODEL_NAME: str = os.getenv("MODEL_NAME") or "meta-llama/Meta-Llama-3-8B-Instruct"
44
+ HF_TOKEN: str = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
45
 
46
  if not HF_TOKEN:
47
+ print("[DEBUG] CRITICAL: HF_TOKEN environment variable is missing.", flush=True)
48
 
49
  TASK_ID: str = os.getenv("TASK_ID", "anomaly_detection_hard")
50
+ BENCHMARK: str = os.getenv("BENCHMARK", "fin_auditor")
51
 
52
  if "easy" in TASK_ID.lower():
53
  _DEFAULT_MAX = 5
 
57
  _DEFAULT_MAX = 20
58
 
59
  MAX_STEPS: int = int(os.getenv("MAX_STEPS", str(_DEFAULT_MAX)))
60
+ TEMPERATURE = 0.0
61
+ MAX_TOKENS = 1500
62
+ SUCCESS_SCORE_THRESHOLD = 0.5 # Need 50%+ to succeed
63
+
64
+ SYSTEM_PROMPT = textwrap.dedent(
65
+ """
66
+ You are a Wall Street Compliance Auditor AI embedded inside a High-Frequency Trading audit engine.
67
+ You MUST think step-by-step in the 'reasoning' field before determining your action.
68
+
69
+ ━━━ DECISION VALUES ━━━
70
+ You must output ONLY raw integers (0 or 1) in the array. NO strings. NO labels.
71
+ 1 : Confirmed anomaly.
72
+ 0 : Trade is clean.
73
+
74
+ ━━━ EVALUATION DIRECTIVE ━━━
75
+ 1. CRITICAL SIGNAL (FLAG): If risk_score > 0.60, output 1.
76
+ 2. NOISE SIGNAL (PASS): If risk_score < 0.30, output 0.
77
+ 3. AMBIGUITY (FLAG): If risk_score is in between, output 1 to be safe.
78
+
79
+ ━━━ CRITICAL JSON FORMAT ━━━
80
+ You MUST respond with a valid JSON object. The decisions array MUST contain exactly the requested number of raw integers. NO trailing commas.
81
+ Example:
82
+ {"reasoning": "Trade 1 has high risk. Trade 2 is safe.", "decisions": [1, 0, 1]}
83
+ """
84
+ ).strip()
85
 
86
+ _last_reasoning: str = ""
 
 
 
 
 
 
 
 
 
87
 
88
+ def log_start(task: str, env: str, model: str) -> None:
89
+ print(f"[START] task={task} env={env} model={model}", flush=True)
 
 
90
 
91
+ def log_step(step: int, action: str, reward: float, done: bool, error: Optional[str]) -> None:
92
+ error_val = error if error else "null"
93
+ done_val = str(done).lower()
94
+ print(
95
+ f"[STEP] step={step} action={action} reward={reward:.2f} done={done_val} error={error_val}",
96
+ flush=True,
97
+ )
98
 
99
+ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
100
+ rewards_str = ",".join(f"{r:.2f}" for r in rewards)
101
+ print(f"[END] success={str(success).lower()} steps={steps} score={score:.3f} rewards={rewards_str}", flush=True)
102
 
103
  def _build_user_prompt(step: int, features: list[list[float]]) -> str:
104
  lines = [
 
116
  lines.append(f"Provide exactly {len(features)} decisions as a JSON object.")
117
  return "\n".join(lines)
118
 
 
 
119
  def _parse_llm_decisions(content: str, expected_count: int) -> list[int]:
120
  global _last_reasoning
121
  stripped = content.strip()
 
157
  clamped.append(1)
158
  return clamped
159
 
160
+ def get_model_message(client: OpenAI, step: int, features: list[list[float]]) -> list[int]:
161
  global _last_reasoning
162
  _last_reasoning = "Fallback triggered."
163
  user_prompt = _build_user_prompt(step, features)
 
165
 
166
  for attempt in range(max_retries):
167
  try:
168
+ completion = client.chat.completions.create(
169
  model=MODEL_NAME,
170
  messages=[
171
  {"role": "system", "content": SYSTEM_PROMPT},
172
  {"role": "user", "content": user_prompt},
173
  ],
174
+ max_tokens=MAX_TOKENS,
175
+ temperature=TEMPERATURE,
176
+ stream=False,
177
  )
178
+ content = (completion.choices[0].message.content or "").strip()
179
  return _parse_llm_decisions(content, len(features))
180
+ except Exception as exc:
181
+ print(f"[DEBUG] Model request failed: {exc}", flush=True)
182
  time.sleep(1)
183
 
184
  fallback_decisions = []
185
  for row in features:
186
  if len(row) >= 4:
 
187
  risk_score = row[3]
188
  fallback_decisions.append(0 if risk_score < 0.30 else 1)
189
  else:
 
191
 
192
  return fallback_decisions
193
 
194
+ def main() -> None:
195
+ client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
196
+
197
+ rewards: List[float] = []
198
+ steps_taken = 0
199
+ score = 0.0
200
+ success = False
201
 
202
+ log_start(task=TASK_ID, env=BENCHMARK, model=MODEL_NAME)
 
203
 
204
+ env = None
205
  try:
206
  env = FinAuditorEnvironment()
207
 
 
208
  if "easy" in TASK_ID.lower():
209
  from tasks.task1_easy import setup_env
210
  setup_env(env)
 
217
 
218
  obs = env.reset()
219
 
220
+ for step in range(1, MAX_STEPS + 1):
 
221
  features = obs.features
222
 
223
  if not features:
224
+ decisions = []
225
  action = AuditorAction(decisions=[])
226
  global _last_reasoning
227
  _last_reasoning = "Empty matrix."
228
  else:
229
+ decisions = get_model_message(client, step, features)
230
  action = AuditorAction(decisions=decisions)
231
 
232
  obs = env.step(action)
233
+
234
+ reward = float(obs.reward) if obs.reward is not None else 0.1
235
+ done = obs.done
236
+ error = getattr(obs, "error", None)
237
 
238
+ rewards.append(reward)
239
+ steps_taken = step
 
240
 
241
+ action_str = ",".join(str(d) for d in decisions) if decisions else "none"
242
+ log_step(step=step, action=action_str, reward=reward, done=done, error=error)
243
 
244
+ if done:
245
  break
246
 
247
+ # Calculate final score based on latest reward (as per Discord guidance clamped strictly)
248
+ raw_score = rewards[-1] if rewards else 0.1
249
+ score = max(0.01, min(0.99, float(raw_score)))
250
+ success = score >= SUCCESS_SCORE_THRESHOLD
251
 
 
 
252
  except Exception as exc:
253
+ print(f"[DEBUG] Execution error: {exc}", flush=True)
254
  traceback.print_exc(file=sys.stderr)
255
  finally:
256
+ try:
257
+ if env and hasattr(env, "close"):
258
+ env.close()
259
+ except Exception as e:
260
+ print(f"[DEBUG] env.close() error: {e}", flush=True)
261
+
262
+ # Ensure fallback score if empty
263
+ if not rewards:
264
+ rewards = [0.1]
265
+ score = 0.1
266
 
267
+ log_end(success=success, steps=steps_taken, score=score, rewards=rewards)
 
268
 
269
  if __name__ == "__main__":
270
+ main()
tasks/task1_easy.py CHANGED
@@ -9,7 +9,7 @@ def get_task_config() -> dict:
9
  "id": TASK_ID,
10
  "difficulty": DIFFICULTY,
11
  "max_steps": MAX_STEPS,
12
- "grader": grader,
13
  "description": "EASY β€” Detect expired/unreconciled trades."
14
  }
15
 
@@ -49,7 +49,7 @@ def run_episode(env, agent_fn) -> dict:
49
  # Always grade β€” even partial data yields a valid score via perfect_signal fallback
50
  from graders.grader_detection import EasyDetectionGrader
51
  grader = EasyDetectionGrader()
52
- final_score = grader.grade(env.state)
53
 
54
  return {
55
  "task": TASK_ID,
 
9
  "id": TASK_ID,
10
  "difficulty": DIFFICULTY,
11
  "max_steps": MAX_STEPS,
12
+ "grader": "graders.grader_detection:EasyDetectionGrader",
13
  "description": "EASY β€” Detect expired/unreconciled trades."
14
  }
15
 
 
49
  # Always grade β€” even partial data yields a valid score via perfect_signal fallback
50
  from graders.grader_detection import EasyDetectionGrader
51
  grader = EasyDetectionGrader()
52
+ final_score = grader.grade(env)
53
 
54
  return {
55
  "task": TASK_ID,
tasks/task2_medium.py CHANGED
@@ -9,7 +9,7 @@ def get_task_config() -> dict:
9
  "id": TASK_ID,
10
  "difficulty": DIFFICULTY,
11
  "max_steps": MAX_STEPS,
12
- "grader": grader,
13
  "description": "MEDIUM β€” Faster ingestion, tighter metrics."
14
  }
15
 
@@ -50,7 +50,7 @@ def run_episode(env, agent_fn) -> dict:
50
  # Always grade β€” even partial data yields a valid score via perfect_signal fallback
51
  from graders.grader_classification import MediumClassificationGrader
52
  grader = MediumClassificationGrader()
53
- final_score = grader.grade(env.state)
54
 
55
  return {
56
  "task": TASK_ID,
 
9
  "id": TASK_ID,
10
  "difficulty": DIFFICULTY,
11
  "max_steps": MAX_STEPS,
12
+ "grader": "graders.grader_classification:MediumClassificationGrader",
13
  "description": "MEDIUM β€” Faster ingestion, tighter metrics."
14
  }
15
 
 
50
  # Always grade β€” even partial data yields a valid score via perfect_signal fallback
51
  from graders.grader_classification import MediumClassificationGrader
52
  grader = MediumClassificationGrader()
53
+ final_score = grader.grade(env)
54
 
55
  return {
56
  "task": TASK_ID,
tasks/task3_hard.py CHANGED
@@ -9,7 +9,7 @@ def get_task_config() -> dict:
9
  "id": TASK_ID,
10
  "difficulty": DIFFICULTY,
11
  "max_steps": MAX_STEPS,
12
- "grader": grader,
13
  "description": "HARD β€” Maximum throughput adversarial trading."
14
  }
15
 
@@ -50,7 +50,7 @@ def run_episode(env, agent_fn) -> dict:
50
  # Always grade β€” even partial data yields a valid score via perfect_signal fallback
51
  from graders.grader_fix import HardFixGrader
52
  grader = HardFixGrader()
53
- final_score = grader.grade(env.state)
54
 
55
  return {
56
  "task": TASK_ID,
 
9
  "id": TASK_ID,
10
  "difficulty": DIFFICULTY,
11
  "max_steps": MAX_STEPS,
12
+ "grader": "graders.grader_fix:HardFixGrader",
13
  "description": "HARD β€” Maximum throughput adversarial trading."
14
  }
15
 
 
50
  # Always grade β€” even partial data yields a valid score via perfect_signal fallback
51
  from graders.grader_fix import HardFixGrader
52
  grader = HardFixGrader()
53
+ final_score = grader.grade(env)
54
 
55
  return {
56
  "task": TASK_ID,