Skip to content

Commit d5f39b4

Browse files
committed
Add a decision box for prompt processing
1 parent cfd4795 commit d5f39b4

15 files changed

Lines changed: 2279 additions & 153 deletions

‎agents.supervisord.conf‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ stderr_logfile=%(here)s/logs/%(program_name)s.log
8585
[program:stf-data-agent]
8686
command=python -u agents/data_agent.py -v
8787
directory=%(ENV_SWF_HOME)s/swf-testbed
88-
environment=SWF_TESTBED_CONFIG="%(ENV_SWF_TESTBED_CONFIG)s"
88+
environment=SWF_TESTBED_CONFIG="%(ENV_SWF_TESTBED_CONFIG)s",SWF_AGENT_MAX_WORKERS="1"
8989
autostart=false
9090
autorestart=true
9191
stopwaitsecs=10
@@ -96,7 +96,7 @@ stderr_logfile=%(here)s/logs/%(program_name)s.log
9696
[program:stf-processing-agent]
9797
command=python -u agents/prompt_processing_agent.py -v
9898
directory=%(ENV_SWF_HOME)s/swf-testbed
99-
environment=SWF_TESTBED_CONFIG="%(ENV_SWF_TESTBED_CONFIG)s"
99+
environment=SWF_TESTBED_CONFIG="%(ENV_SWF_TESTBED_CONFIG)s",SWF_AGENT_MAX_WORKERS="1"
100100
autostart=false
101101
autorestart=true
102102
stopwaitsecs=10

‎agents/agent_config_helpers.py‎

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import os
2+
import tomllib
3+
4+
5+
class PromptProcessingConfigMixin:
6+
"""Shared prompt-processing config helpers for local testbed agents."""
7+
8+
def _prompt_processing_config_path(self):
9+
return os.path.join(os.path.dirname(os.path.dirname(__file__)), "workflows", "prompt_processing.toml")
10+
11+
def _load_prompt_processing_section(self, config_path, warn=False):
12+
if not config_path:
13+
return {}
14+
try:
15+
with open(config_path, "rb") as config_file:
16+
return tomllib.load(config_file).get("prompt_processing", {})
17+
except (OSError, TypeError, tomllib.TOMLDecodeError) as e:
18+
if warn:
19+
self.logger.warning(
20+
f"Could not load prompt_processing config from {config_path}: {e}",
21+
extra=self._log_extra()
22+
)
23+
return {}
24+
25+
def _load_prompt_processing_config(self):
26+
"""Load prompt-processing settings, with workflow defaults plus active config overrides."""
27+
prompt_config = self._load_prompt_processing_section(self._prompt_processing_config_path(), warn=True)
28+
active_config = self._load_prompt_processing_section(self.config_path, warn=True)
29+
prompt_config.update(active_config)
30+
return prompt_config
31+
32+
def _config_bool(self, config, key, env_var, default):
33+
"""Read a boolean setting from config, with an environment override."""
34+
value = os.getenv(env_var, config.get(key, default))
35+
if isinstance(value, bool):
36+
return value
37+
if isinstance(value, str):
38+
return value.strip().lower() in {"1", "true", "yes", "on"}
39+
return bool(value)
40+
41+
def _config_int(self, config, key, env_var, default):
42+
"""Read an integer setting from config, with an environment override."""
43+
value = os.getenv(env_var, config.get(key, default))
44+
try:
45+
return int(value)
46+
except (TypeError, ValueError):
47+
self.logger.warning(
48+
f"Invalid {key} value {value!r}; using default {default}",
49+
extra=self._log_extra()
50+
)
51+
return default
52+
53+
def _config_list(self, config, key, env_var, default):
54+
"""Read a comma-separated list setting from config, with an environment override."""
55+
value = os.getenv(env_var, config.get(key, default))
56+
if isinstance(value, str):
57+
return [item.strip() for item in value.split(",") if item.strip()]
58+
if isinstance(value, (list, tuple)):
59+
return [str(item).strip() for item in value if str(item).strip()]
60+
return list(default)
61+
62+
def _message_bool(self, message_data, key, default):
63+
value = message_data.get(key, default)
64+
if isinstance(value, bool):
65+
return value
66+
if isinstance(value, str):
67+
return value.strip().lower() in {"1", "true", "yes", "on"}
68+
return bool(value)
69+
70+
71+
class DecisionDatasetNamingMixin:
72+
"""Shared decision-box message and dataset helpers."""
73+
74+
def _decision_box_context_for_run(self, run_id):
75+
return {}
76+
77+
def _decision_box_enabled_for_message(self, message_data, run_id=None):
78+
if "decision_box_enabled" in message_data:
79+
return self._message_bool(message_data, "decision_box_enabled", self.decision_box_enabled)
80+
if run_id is not None:
81+
context = self._decision_box_context_for_run(run_id)
82+
if "decision_box_enabled" in context:
83+
return bool(context["decision_box_enabled"])
84+
return self.decision_box_enabled
85+
86+
def _non_decision_box_site_for_message(self, message_data, run_id=None):
87+
site = message_data.get("non_decision_box_site")
88+
if site:
89+
return str(site).strip()
90+
if run_id is not None:
91+
context = self._decision_box_context_for_run(run_id)
92+
site = context.get("non_decision_box_site")
93+
if site:
94+
return str(site).strip()
95+
return getattr(self, "non_decision_box_site", None)
96+
97+
def _run_dataset_name(self, run_number=None):
98+
dataset = getattr(self, "dataset", None)
99+
if dataset:
100+
return dataset
101+
if run_number is not None:
102+
return f"swf.{run_number}.run"
103+
return ""
104+
105+
def _run_dataset_did(self, run_number=None):
106+
return f"{self.decision_box_rucio_scope}:{self._run_dataset_name(run_number)}"
107+
108+
def _input_dataset_name_for_site(self, run_number, site_name):
109+
run_dataset_name = f"swf.{run_number}.run"
110+
if self.decision_box_site_dataset_template:
111+
return self.decision_box_site_dataset_template.format(
112+
run_dataset_name=run_dataset_name,
113+
run_number=run_number,
114+
site_name=site_name,
115+
site=site_name,
116+
)
117+
return f"{self._run_dataset_name(run_number)}.{site_name}"
118+
119+
def _input_dataset_did_for_site(self, run_number, site_name):
120+
return f"{self.decision_box_rucio_scope}:{self._input_dataset_name_for_site(run_number, site_name)}"
121+
122+
def _site_name_for_dataset(self, run_number, dataset_did):
123+
for site_name in self.decision_box_sites:
124+
if dataset_did == self._input_dataset_did_for_site(run_number, site_name):
125+
return site_name
126+
return None

0 commit comments

Comments
 (0)