agent-apprenticeship 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -197
- package/bin/agent-apprenticeship.js +85 -37
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/agent_apprenticeship_trace/__init__.py +1 -1
- package/src/agent_apprenticeship_trace/actual_outputs_normalizer.py +104 -28
- package/src/agent_apprenticeship_trace/apprentice_adapters.py +3 -1
- package/src/agent_apprenticeship_trace/artifact_resolver.py +6 -0
- package/src/agent_apprenticeship_trace/bundle_exporter.py +132 -2
- package/src/agent_apprenticeship_trace/cli.py +1229 -269
- package/src/agent_apprenticeship_trace/codex_runner.py +89 -6
- package/src/agent_apprenticeship_trace/config.py +251 -32
- package/src/agent_apprenticeship_trace/ecosystem_r2.py +515 -0
- package/src/agent_apprenticeship_trace/env.py +5 -5
- package/src/agent_apprenticeship_trace/evaluator.py +127 -11
- package/src/agent_apprenticeship_trace/grader.py +12 -11
- package/src/agent_apprenticeship_trace/learning.py +270 -1
- package/src/agent_apprenticeship_trace/llm_output_normalizer.py +8 -7
- package/src/agent_apprenticeship_trace/loop.py +103 -4
- package/src/agent_apprenticeship_trace/loop_review.py +686 -0
- package/src/agent_apprenticeship_trace/mentor_checkpoints.py +49 -21
- package/src/agent_apprenticeship_trace/openai_structured.py +84 -14
- package/src/agent_apprenticeship_trace/package_exporter.py +1 -1
- package/src/agent_apprenticeship_trace/progress.py +2 -1
- package/src/agent_apprenticeship_trace/public_run.py +369 -57
- package/src/agent_apprenticeship_trace/public_sanitizer.py +40 -3
- package/src/agent_apprenticeship_trace/rubric_generation.py +11 -10
- package/src/agent_apprenticeship_trace/schemas.py +378 -3
- package/src/agent_apprenticeship_trace/task_intake.py +43 -9
- package/src/agent_apprenticeship_trace/tdo.py +2304 -0
- package/src/agent_apprenticeship_trace/trace_normalizer.py +351 -17
- package/src/agent_apprenticeship_trace/trace_prompt.py +38 -11
- package/src/agent_apprenticeship_trace/training_signals.py +1 -1
- package/src/agent_apprenticeship_trace/verifier.py +12 -6
|
@@ -16,23 +16,93 @@ from .io import read_json, write_json
|
|
|
16
16
|
from .recipes import MODEL_PROVIDER_RECIPES, WORKER_AGENT_RECIPES
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
ApprenticeshipMode = Literal["autonomous", "expert_led", "org_custom"]
|
|
19
20
|
MentorMode = Literal["model_assisted", "expert_led", "hybrid"]
|
|
20
21
|
SensitiveInfoMasking = Literal["standard", "no_masking"]
|
|
21
|
-
EcosystemAutoShare = Literal["manual", "
|
|
22
|
+
EcosystemAutoShare = Literal["manual", "automatic", "disabled"]
|
|
23
|
+
TrainingContributionMode = Literal["public_ecosystem", "private_internal_only"]
|
|
24
|
+
EcosystemStorageBackend = Literal["forsy-r2", "github"]
|
|
22
25
|
EvaluationMode = Literal["model-assisted", "expert-led", "hybrid"]
|
|
23
26
|
DataSharingLevel = Literal["standard", "full-context"]
|
|
24
27
|
|
|
28
|
+
APPRENTICESHIP_MODES: tuple[str, ...] = ("autonomous", "expert_led", "org_custom")
|
|
25
29
|
MENTOR_MODES: tuple[str, ...] = ("model_assisted", "expert_led", "hybrid")
|
|
26
30
|
SENSITIVE_INFO_MASKING_LEVELS: tuple[str, ...] = ("standard", "no_masking")
|
|
27
|
-
ECOSYSTEM_AUTO_SHARE_MODES: tuple[str, ...] = ("manual", "
|
|
31
|
+
ECOSYSTEM_AUTO_SHARE_MODES: tuple[str, ...] = ("manual", "automatic", "disabled")
|
|
32
|
+
TRAINING_CONTRIBUTION_MODES: tuple[str, ...] = ("public_ecosystem", "private_internal_only")
|
|
28
33
|
EVALUATION_MODES: tuple[str, ...] = ("model-assisted", "expert-led", "hybrid")
|
|
29
34
|
DATA_SHARING_LEVELS: tuple[str, ...] = ("standard", "full-context")
|
|
30
35
|
DEFAULT_APP_HOME = Path("~/.agent-apprenticeship").expanduser()
|
|
31
36
|
DEFAULT_PUBLIC_ECOSYSTEM_REPO = "Forsy-AI/agent-apprenticeship"
|
|
32
37
|
DEFAULT_PUBLIC_ECOSYSTEM_URL = f"https://github.com/{DEFAULT_PUBLIC_ECOSYSTEM_REPO}"
|
|
38
|
+
DEFAULT_ECOSYSTEM_STORAGE_BACKEND = "forsy-r2"
|
|
39
|
+
DEFAULT_R2_BUCKET = "apprenticeship-dev"
|
|
40
|
+
DEFAULT_R2_INDEX_PREFIX = "indexes"
|
|
41
|
+
DEFAULT_R2_CONTRIBUTION_PREFIX = "contributions/packages"
|
|
42
|
+
DEFAULT_R2_SEED_PREFIX = "contributions/seed_dataset"
|
|
43
|
+
DEFAULT_R2_API_BASE = "https://agent-apprenticeship-ingest.sai-1c1.workers.dev"
|
|
33
44
|
_SETTINGS_OVERRIDE: ContextVar[Any] = ContextVar("agent_apprenticeship_settings_override", default=None)
|
|
34
45
|
|
|
35
46
|
|
|
47
|
+
def normalize_apprenticeship_mode(value: str | None, default: str = "autonomous") -> str:
|
|
48
|
+
if value is None or str(value).strip() == "":
|
|
49
|
+
return default
|
|
50
|
+
normalized = str(value).strip().lower().replace("-", "_").replace(" ", "_")
|
|
51
|
+
aliases = {
|
|
52
|
+
"autonomous": "autonomous",
|
|
53
|
+
"autonomous_apprenticeship": "autonomous",
|
|
54
|
+
"model": "autonomous",
|
|
55
|
+
"model_assisted": "autonomous",
|
|
56
|
+
"model_assisted_automated": "autonomous",
|
|
57
|
+
"modelassisted": "autonomous",
|
|
58
|
+
"automated": "autonomous",
|
|
59
|
+
"expert": "expert_led",
|
|
60
|
+
"expert_led": "expert_led",
|
|
61
|
+
"expert_led_apprenticeship": "expert_led",
|
|
62
|
+
"expert_led_manual": "expert_led",
|
|
63
|
+
"manual": "expert_led",
|
|
64
|
+
"human": "expert_led",
|
|
65
|
+
"hybrid": "expert_led",
|
|
66
|
+
"org": "org_custom",
|
|
67
|
+
"organization": "org_custom",
|
|
68
|
+
"organization_custom": "org_custom",
|
|
69
|
+
"org_custom": "org_custom",
|
|
70
|
+
"custom_org": "org_custom",
|
|
71
|
+
"custom": "org_custom",
|
|
72
|
+
}
|
|
73
|
+
normalized = aliases.get(normalized, normalized)
|
|
74
|
+
if normalized not in APPRENTICESHIP_MODES:
|
|
75
|
+
raise ValueError(f"Unsupported Apprenticeship Mode: {value}")
|
|
76
|
+
return normalized
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def apprenticeship_mode_display(value: str | None) -> str:
|
|
80
|
+
normalized = normalize_apprenticeship_mode(value)
|
|
81
|
+
return {
|
|
82
|
+
"autonomous": "Autonomous Apprenticeship",
|
|
83
|
+
"expert_led": "Expert-Led Apprenticeship",
|
|
84
|
+
"org_custom": "Organization Custom",
|
|
85
|
+
}[normalized]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def apprenticeship_mode_to_mentor_mode(value: str | None) -> str:
|
|
89
|
+
normalized = normalize_apprenticeship_mode(value)
|
|
90
|
+
return {
|
|
91
|
+
"autonomous": "model_assisted",
|
|
92
|
+
"expert_led": "expert_led",
|
|
93
|
+
"org_custom": "expert_led",
|
|
94
|
+
}[normalized]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def mentor_mode_to_apprenticeship_mode(value: str | None) -> str:
|
|
98
|
+
normalized = normalize_mentor_mode(value)
|
|
99
|
+
return {
|
|
100
|
+
"model_assisted": "autonomous",
|
|
101
|
+
"expert_led": "expert_led",
|
|
102
|
+
"hybrid": "expert_led",
|
|
103
|
+
}[normalized]
|
|
104
|
+
|
|
105
|
+
|
|
36
106
|
def normalize_mentor_mode(value: str | None, default: str = "model_assisted") -> str:
|
|
37
107
|
if value is None or str(value).strip() == "":
|
|
38
108
|
return default
|
|
@@ -50,7 +120,7 @@ def normalize_mentor_mode(value: str | None, default: str = "model_assisted") ->
|
|
|
50
120
|
}
|
|
51
121
|
normalized = aliases.get(normalized, normalized)
|
|
52
122
|
if normalized not in MENTOR_MODES:
|
|
53
|
-
raise ValueError(f"Unsupported
|
|
123
|
+
raise ValueError(f"Unsupported apprenticeship mode: {value}")
|
|
54
124
|
return normalized
|
|
55
125
|
|
|
56
126
|
|
|
@@ -68,12 +138,7 @@ def evaluation_mode_to_mentor_mode(value: str | None) -> str:
|
|
|
68
138
|
|
|
69
139
|
|
|
70
140
|
def mentor_mode_display(value: str | None) -> str:
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
"model_assisted": "model-assisted",
|
|
74
|
-
"expert_led": "expert-led",
|
|
75
|
-
"hybrid": "hybrid",
|
|
76
|
-
}[normalized]
|
|
141
|
+
return apprenticeship_mode_display(mentor_mode_to_apprenticeship_mode(value))
|
|
77
142
|
|
|
78
143
|
|
|
79
144
|
def normalize_sensitive_info_masking(value: str | None, default: str = "standard") -> str:
|
|
@@ -110,31 +175,100 @@ def normalize_ecosystem_auto_share(value: str | None, default: str = "manual") -
|
|
|
110
175
|
normalized = str(value).strip().lower().replace("-", "_").replace(" ", "_")
|
|
111
176
|
aliases = {
|
|
112
177
|
"manual": "manual",
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"prompt": "ask",
|
|
117
|
-
"ask_before_sharing": "ask",
|
|
178
|
+
"ask": "manual",
|
|
179
|
+
"prompt": "manual",
|
|
180
|
+
"ask_before_sharing": "manual",
|
|
118
181
|
"share_automatically": "automatic",
|
|
119
182
|
"automatic": "automatic",
|
|
120
183
|
"auto": "automatic",
|
|
121
184
|
"on": "automatic",
|
|
185
|
+
"disabled": "disabled",
|
|
186
|
+
"disable": "disabled",
|
|
187
|
+
"off": "disabled",
|
|
188
|
+
"none": "disabled",
|
|
122
189
|
}
|
|
123
190
|
normalized = aliases.get(normalized, normalized)
|
|
124
191
|
if normalized not in ECOSYSTEM_AUTO_SHARE_MODES:
|
|
125
|
-
raise ValueError(f"Unsupported
|
|
192
|
+
raise ValueError(f"Unsupported ecosystem sharing setting: {value}")
|
|
126
193
|
return normalized
|
|
127
194
|
|
|
128
195
|
|
|
129
196
|
def ecosystem_auto_share_display(value: str | None) -> str:
|
|
130
197
|
normalized = normalize_ecosystem_auto_share(value)
|
|
131
198
|
return {
|
|
132
|
-
"manual": "
|
|
133
|
-
"
|
|
134
|
-
"
|
|
199
|
+
"manual": "manual",
|
|
200
|
+
"automatic": "automatic",
|
|
201
|
+
"disabled": "disabled",
|
|
135
202
|
}[normalized]
|
|
136
203
|
|
|
137
204
|
|
|
205
|
+
def normalize_training_contribution_mode(value: str | None, default: str = "public_ecosystem") -> str:
|
|
206
|
+
if value is None or str(value).strip() == "":
|
|
207
|
+
return default
|
|
208
|
+
normalized = str(value).strip().lower().replace("-", "_").replace(" ", "_")
|
|
209
|
+
aliases = {
|
|
210
|
+
"public": "public_ecosystem",
|
|
211
|
+
"public_ecosystem": "public_ecosystem",
|
|
212
|
+
"public_ecosystem_default": "public_ecosystem",
|
|
213
|
+
"ecosystem": "public_ecosystem",
|
|
214
|
+
"share": "public_ecosystem",
|
|
215
|
+
"shared": "public_ecosystem",
|
|
216
|
+
"automatic": "public_ecosystem",
|
|
217
|
+
"auto": "public_ecosystem",
|
|
218
|
+
"on": "public_ecosystem",
|
|
219
|
+
"private": "private_internal_only",
|
|
220
|
+
"private_internal": "private_internal_only",
|
|
221
|
+
"private_internal_only": "private_internal_only",
|
|
222
|
+
"internal": "private_internal_only",
|
|
223
|
+
"local": "private_internal_only",
|
|
224
|
+
"manual": "private_internal_only",
|
|
225
|
+
"ask": "private_internal_only",
|
|
226
|
+
"disabled": "private_internal_only",
|
|
227
|
+
"disable": "private_internal_only",
|
|
228
|
+
"off": "private_internal_only",
|
|
229
|
+
"none": "private_internal_only",
|
|
230
|
+
}
|
|
231
|
+
normalized = aliases.get(normalized, normalized)
|
|
232
|
+
if normalized not in TRAINING_CONTRIBUTION_MODES:
|
|
233
|
+
raise ValueError(f"Unsupported Agent Training Contribution Mode: {value}")
|
|
234
|
+
return normalized
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def training_contribution_mode_display(value: str | None) -> str:
|
|
238
|
+
normalized = normalize_training_contribution_mode(value)
|
|
239
|
+
return {
|
|
240
|
+
"public_ecosystem": "Public Ecosystem",
|
|
241
|
+
"private_internal_only": "Private Internal Only",
|
|
242
|
+
}[normalized]
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def training_contribution_to_auto_share(value: str | None) -> str:
|
|
246
|
+
return "automatic" if normalize_training_contribution_mode(value) == "public_ecosystem" else "disabled"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def auto_share_to_training_contribution(value: str | None) -> str:
|
|
250
|
+
return "private_internal_only" if normalize_ecosystem_auto_share(value) == "disabled" else "public_ecosystem"
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def normalize_ecosystem_storage(value: str | None, default: str = DEFAULT_ECOSYSTEM_STORAGE_BACKEND) -> str:
|
|
254
|
+
if value is None or str(value).strip() == "":
|
|
255
|
+
return default
|
|
256
|
+
normalized = str(value).strip().lower().replace("_", "-")
|
|
257
|
+
aliases = {
|
|
258
|
+
"r2": "forsy-r2",
|
|
259
|
+
"cloudflare-r2": "forsy-r2",
|
|
260
|
+
"cloudflare_r2": "forsy-r2",
|
|
261
|
+
"forsy-r2": "forsy-r2",
|
|
262
|
+
"github": "github",
|
|
263
|
+
"github-issue": "github",
|
|
264
|
+
"legacy-github": "github",
|
|
265
|
+
}
|
|
266
|
+
normalized = aliases.get(normalized, normalized)
|
|
267
|
+
if normalized not in {"forsy-r2", "github"}:
|
|
268
|
+
raise ValueError(f"Unsupported ecosystem storage backend: {value}")
|
|
269
|
+
return normalized
|
|
270
|
+
|
|
271
|
+
|
|
138
272
|
class Settings(BaseModel):
|
|
139
273
|
# Public product settings.
|
|
140
274
|
app_home: Path = DEFAULT_APP_HOME
|
|
@@ -145,6 +279,7 @@ class Settings(BaseModel):
|
|
|
145
279
|
model_provider: str | None = None
|
|
146
280
|
model_provider_api_key_env: str | None = None
|
|
147
281
|
model_provider_model: str | None = None
|
|
282
|
+
apprenticeship_mode: ApprenticeshipMode = "autonomous"
|
|
148
283
|
mentor_mode: MentorMode = "model_assisted"
|
|
149
284
|
sensitive_info_masking: SensitiveInfoMasking = "standard"
|
|
150
285
|
evaluation_mode: EvaluationMode = "model-assisted"
|
|
@@ -159,7 +294,14 @@ class Settings(BaseModel):
|
|
|
159
294
|
mentor_model_provider_readiness_reason: str | None = None
|
|
160
295
|
ecosystem_repo: str | None = DEFAULT_PUBLIC_ECOSYSTEM_REPO
|
|
161
296
|
ecosystem_repo_path: Path | None = None
|
|
162
|
-
|
|
297
|
+
training_contribution_mode: TrainingContributionMode = "public_ecosystem"
|
|
298
|
+
ecosystem_auto_share: EcosystemAutoShare = "automatic"
|
|
299
|
+
ecosystem_storage_backend: EcosystemStorageBackend = DEFAULT_ECOSYSTEM_STORAGE_BACKEND
|
|
300
|
+
r2_api_url: str | None = DEFAULT_R2_API_BASE
|
|
301
|
+
r2_bucket: str = DEFAULT_R2_BUCKET
|
|
302
|
+
r2_index_prefix: str = DEFAULT_R2_INDEX_PREFIX
|
|
303
|
+
r2_contribution_prefix: str = DEFAULT_R2_CONTRIBUTION_PREFIX
|
|
304
|
+
r2_seed_prefix: str = DEFAULT_R2_SEED_PREFIX
|
|
163
305
|
|
|
164
306
|
# Compatibility settings used by the existing internal pipeline.
|
|
165
307
|
openai_api_key: str | None = None
|
|
@@ -264,13 +406,19 @@ def get_settings(root: Path | None = None) -> Settings:
|
|
|
264
406
|
)
|
|
265
407
|
legacy_iterations = _int_env("AA_MAX_ITERATIONS", int(stored.get("max_iterations") or 3))
|
|
266
408
|
openai_model = os.getenv("AA_OPENAI_MODEL", stored.get("openai_model") or "gpt-5-mini")
|
|
267
|
-
|
|
409
|
+
new_mode_source = os.getenv("AA_APPRENTICESHIP_MODE") or stored.get("apprenticeship_mode")
|
|
410
|
+
legacy_mode_source = (
|
|
268
411
|
os.getenv("AA_MENTOR_MODE")
|
|
269
412
|
or stored.get("mentor_mode")
|
|
270
413
|
or os.getenv("AA_EVALUATION_MODE")
|
|
271
414
|
or stored.get("evaluation_mode")
|
|
272
|
-
or "model_assisted"
|
|
273
415
|
)
|
|
416
|
+
apprenticeship_mode = normalize_apprenticeship_mode(new_mode_source or legacy_mode_source or "autonomous")
|
|
417
|
+
mentor_mode = apprenticeship_mode_to_mentor_mode(apprenticeship_mode)
|
|
418
|
+
if not new_mode_source and legacy_mode_source:
|
|
419
|
+
legacy_mentor_mode = normalize_mentor_mode(legacy_mode_source)
|
|
420
|
+
if legacy_mentor_mode == "hybrid":
|
|
421
|
+
mentor_mode = "hybrid"
|
|
274
422
|
sensitive_info_masking = normalize_sensitive_info_masking(
|
|
275
423
|
os.getenv("AA_SENSITIVE_INFO_MASKING")
|
|
276
424
|
or stored.get("sensitive_info_masking")
|
|
@@ -278,6 +426,18 @@ def get_settings(root: Path | None = None) -> Settings:
|
|
|
278
426
|
or stored.get("data_sharing_level")
|
|
279
427
|
or "standard"
|
|
280
428
|
)
|
|
429
|
+
auto_share_source = os.getenv("AA_ECOSYSTEM_AUTO_SHARE") or stored.get("ecosystem_auto_share")
|
|
430
|
+
training_contribution_source = os.getenv("AA_TRAINING_CONTRIBUTION_MODE") or stored.get("training_contribution_mode")
|
|
431
|
+
if training_contribution_source:
|
|
432
|
+
training_contribution_mode = normalize_training_contribution_mode(training_contribution_source)
|
|
433
|
+
elif auto_share_source:
|
|
434
|
+
training_contribution_mode = auto_share_to_training_contribution(auto_share_source)
|
|
435
|
+
else:
|
|
436
|
+
training_contribution_mode = "public_ecosystem"
|
|
437
|
+
if auto_share_source:
|
|
438
|
+
ecosystem_auto_share = normalize_ecosystem_auto_share(auto_share_source)
|
|
439
|
+
else:
|
|
440
|
+
ecosystem_auto_share = training_contribution_to_auto_share(training_contribution_mode)
|
|
281
441
|
|
|
282
442
|
return Settings(
|
|
283
443
|
app_home=home,
|
|
@@ -288,6 +448,7 @@ def get_settings(root: Path | None = None) -> Settings:
|
|
|
288
448
|
model_provider=provider,
|
|
289
449
|
model_provider_api_key_env=provider_key_env,
|
|
290
450
|
model_provider_model=provider_model,
|
|
451
|
+
apprenticeship_mode=apprenticeship_mode,
|
|
291
452
|
mentor_mode=mentor_mode,
|
|
292
453
|
sensitive_info_masking=sensitive_info_masking,
|
|
293
454
|
evaluation_mode=mentor_mode_to_evaluation_mode(mentor_mode),
|
|
@@ -304,9 +465,24 @@ def get_settings(root: Path | None = None) -> Settings:
|
|
|
304
465
|
ecosystem_repo_path=Path(os.getenv("AA_ECOSYSTEM_REPO_PATH") or stored.get("ecosystem_repo_path")).expanduser()
|
|
305
466
|
if (os.getenv("AA_ECOSYSTEM_REPO_PATH") or stored.get("ecosystem_repo_path"))
|
|
306
467
|
else None,
|
|
307
|
-
|
|
308
|
-
|
|
468
|
+
training_contribution_mode=training_contribution_mode,
|
|
469
|
+
ecosystem_auto_share=ecosystem_auto_share,
|
|
470
|
+
ecosystem_storage_backend=normalize_ecosystem_storage(
|
|
471
|
+
os.getenv("AA_R2_STORAGE_BACKEND")
|
|
472
|
+
or os.getenv("AA_ECOSYSTEM_STORAGE_BACKEND")
|
|
473
|
+
or stored.get("ecosystem_storage_backend")
|
|
474
|
+
or DEFAULT_ECOSYSTEM_STORAGE_BACKEND
|
|
475
|
+
),
|
|
476
|
+
r2_api_url=(
|
|
477
|
+
os.getenv("AA_R2_API_BASE")
|
|
478
|
+
or os.getenv("AA_R2_API_URL")
|
|
479
|
+
or stored.get("r2_api_url")
|
|
480
|
+
or DEFAULT_R2_API_BASE
|
|
309
481
|
),
|
|
482
|
+
r2_bucket=os.getenv("AA_R2_BUCKET") or stored.get("r2_bucket") or DEFAULT_R2_BUCKET,
|
|
483
|
+
r2_index_prefix=os.getenv("AA_R2_INDEX_PREFIX") or stored.get("r2_index_prefix") or DEFAULT_R2_INDEX_PREFIX,
|
|
484
|
+
r2_contribution_prefix=os.getenv("AA_R2_CONTRIBUTION_PREFIX") or stored.get("r2_contribution_prefix") or DEFAULT_R2_CONTRIBUTION_PREFIX,
|
|
485
|
+
r2_seed_prefix=os.getenv("AA_R2_SEED_PREFIX") or stored.get("r2_seed_prefix") or DEFAULT_R2_SEED_PREFIX,
|
|
310
486
|
openai_api_key=os.getenv("OPENAI_API_KEY"),
|
|
311
487
|
openai_model=openai_model,
|
|
312
488
|
worker_runner=os.getenv("AA_WORKER_RUNNER", os.getenv("AA_TRACE_WORKER_RUNNER", stored.get("worker_runner") or worker_agent)),
|
|
@@ -355,18 +531,45 @@ def update_settings(**updates: Any) -> Settings:
|
|
|
355
531
|
settings = get_settings()
|
|
356
532
|
data = settings.model_dump()
|
|
357
533
|
clean_updates = {k: v for k, v in updates.items() if v is not None}
|
|
534
|
+
legacy_requested_mode = None
|
|
535
|
+
if "apprenticeship_mode" not in clean_updates:
|
|
536
|
+
if "mentor_mode" in clean_updates:
|
|
537
|
+
legacy_requested_mode = clean_updates["mentor_mode"]
|
|
538
|
+
elif "evaluation_mode" in clean_updates:
|
|
539
|
+
legacy_requested_mode = evaluation_mode_to_mentor_mode(clean_updates["evaluation_mode"])
|
|
540
|
+
if "mentor_mode" in clean_updates and "apprenticeship_mode" not in clean_updates:
|
|
541
|
+
clean_updates["apprenticeship_mode"] = mentor_mode_to_apprenticeship_mode(clean_updates["mentor_mode"])
|
|
358
542
|
if "evaluation_mode" in clean_updates and "mentor_mode" not in clean_updates:
|
|
359
|
-
clean_updates["
|
|
543
|
+
clean_updates["apprenticeship_mode"] = mentor_mode_to_apprenticeship_mode(
|
|
544
|
+
evaluation_mode_to_mentor_mode(clean_updates["evaluation_mode"])
|
|
545
|
+
)
|
|
546
|
+
if "apprenticeship_mode" in clean_updates:
|
|
547
|
+
clean_updates["apprenticeship_mode"] = normalize_apprenticeship_mode(clean_updates["apprenticeship_mode"])
|
|
548
|
+
clean_updates["mentor_mode"] = apprenticeship_mode_to_mentor_mode(clean_updates["apprenticeship_mode"])
|
|
549
|
+
clean_updates["evaluation_mode"] = mentor_mode_to_evaluation_mode(clean_updates["mentor_mode"])
|
|
360
550
|
if "mentor_mode" in clean_updates:
|
|
361
551
|
clean_updates["mentor_mode"] = normalize_mentor_mode(clean_updates["mentor_mode"])
|
|
552
|
+
clean_updates["apprenticeship_mode"] = mentor_mode_to_apprenticeship_mode(clean_updates["mentor_mode"])
|
|
362
553
|
clean_updates["evaluation_mode"] = mentor_mode_to_evaluation_mode(clean_updates["mentor_mode"])
|
|
554
|
+
if legacy_requested_mode and normalize_mentor_mode(legacy_requested_mode) == "hybrid":
|
|
555
|
+
clean_updates["apprenticeship_mode"] = "expert_led"
|
|
556
|
+
clean_updates["mentor_mode"] = "hybrid"
|
|
557
|
+
clean_updates["evaluation_mode"] = "hybrid"
|
|
363
558
|
if "data_sharing_level" in clean_updates and "sensitive_info_masking" not in clean_updates:
|
|
364
559
|
clean_updates["sensitive_info_masking"] = data_sharing_to_sensitive_info_masking(clean_updates["data_sharing_level"])
|
|
365
560
|
if "sensitive_info_masking" in clean_updates:
|
|
366
561
|
clean_updates["sensitive_info_masking"] = normalize_sensitive_info_masking(clean_updates["sensitive_info_masking"])
|
|
367
562
|
clean_updates["data_sharing_level"] = sensitive_info_masking_to_data_sharing(clean_updates["sensitive_info_masking"])
|
|
563
|
+
if "ecosystem_auto_share" in clean_updates and "training_contribution_mode" not in clean_updates:
|
|
564
|
+
clean_updates["training_contribution_mode"] = auto_share_to_training_contribution(clean_updates["ecosystem_auto_share"])
|
|
565
|
+
if "training_contribution_mode" in clean_updates:
|
|
566
|
+
clean_updates["training_contribution_mode"] = normalize_training_contribution_mode(clean_updates["training_contribution_mode"])
|
|
567
|
+
if "ecosystem_auto_share" not in clean_updates:
|
|
568
|
+
clean_updates["ecosystem_auto_share"] = training_contribution_to_auto_share(clean_updates["training_contribution_mode"])
|
|
368
569
|
if "ecosystem_auto_share" in clean_updates:
|
|
369
570
|
clean_updates["ecosystem_auto_share"] = normalize_ecosystem_auto_share(clean_updates["ecosystem_auto_share"])
|
|
571
|
+
if "ecosystem_storage_backend" in clean_updates:
|
|
572
|
+
clean_updates["ecosystem_storage_backend"] = normalize_ecosystem_storage(clean_updates["ecosystem_storage_backend"])
|
|
370
573
|
if "worker_agent" in clean_updates and "worker_runner" not in clean_updates:
|
|
371
574
|
clean_updates["worker_runner"] = clean_updates["worker_agent"]
|
|
372
575
|
clean_updates["reviser_runner"] = clean_updates["worker_agent"]
|
|
@@ -377,15 +580,19 @@ def update_settings(**updates: Any) -> Settings:
|
|
|
377
580
|
if updated.model_provider is not None and updated.model_provider not in MODEL_PROVIDER_RECIPES:
|
|
378
581
|
raise ValueError(f"Unsupported Mentor Model Provider: {updated.model_provider}")
|
|
379
582
|
if updated.evaluation_mode not in EVALUATION_MODES:
|
|
380
|
-
raise ValueError(f"Unsupported
|
|
583
|
+
raise ValueError(f"Unsupported Apprenticeship Mode: {updated.apprenticeship_mode}")
|
|
381
584
|
if updated.data_sharing_level not in DATA_SHARING_LEVELS:
|
|
382
585
|
raise ValueError(f"Unsupported Sensitive Info Masking setting: {updated.sensitive_info_masking}")
|
|
383
586
|
if updated.mentor_mode not in MENTOR_MODES:
|
|
384
587
|
raise ValueError(f"Unsupported mentor mode: {updated.mentor_mode}")
|
|
588
|
+
if updated.apprenticeship_mode not in APPRENTICESHIP_MODES:
|
|
589
|
+
raise ValueError(f"Unsupported Apprenticeship Mode: {updated.apprenticeship_mode}")
|
|
385
590
|
if updated.sensitive_info_masking not in SENSITIVE_INFO_MASKING_LEVELS:
|
|
386
591
|
raise ValueError(f"Unsupported sensitive info masking setting: {updated.sensitive_info_masking}")
|
|
387
592
|
if updated.ecosystem_auto_share not in ECOSYSTEM_AUTO_SHARE_MODES:
|
|
388
|
-
raise ValueError(f"Unsupported
|
|
593
|
+
raise ValueError(f"Unsupported ecosystem sharing setting: {updated.ecosystem_auto_share}")
|
|
594
|
+
if updated.training_contribution_mode not in TRAINING_CONTRIBUTION_MODES:
|
|
595
|
+
raise ValueError(f"Unsupported Agent Training Contribution Mode: {updated.training_contribution_mode}")
|
|
389
596
|
if updated.worker_agent == "custom":
|
|
390
597
|
template = updated.custom_worker_command_template or ""
|
|
391
598
|
missing = [token for token in ("{workspace}", "{prompt_file}") if token not in template]
|
|
@@ -575,12 +782,18 @@ def public_settings(settings: Settings | None = None) -> dict[str, Any]:
|
|
|
575
782
|
"mentor_model_provider_status_reason": provider_status.get("reason"),
|
|
576
783
|
"mentor_model_provider_api_key_env": provider_status.get("api_key_env_var"),
|
|
577
784
|
"mentor_model_provider_api_key_visible": provider_status.get("api_key_visible"),
|
|
578
|
-
"
|
|
785
|
+
"apprenticeship_mode": s.apprenticeship_mode,
|
|
579
786
|
"sensitive_info_masking": s.sensitive_info_masking,
|
|
580
787
|
"max_improvement_loops": s.max_improvement_loops,
|
|
581
788
|
"ecosystem_repo": s.ecosystem_repo,
|
|
582
789
|
"ecosystem_repo_path": str(s.ecosystem_repo_path) if s.ecosystem_repo_path else None,
|
|
583
|
-
"
|
|
790
|
+
"training_contribution_mode": s.training_contribution_mode,
|
|
791
|
+
"ecosystem_storage_backend": s.ecosystem_storage_backend,
|
|
792
|
+
"r2_api_url": s.r2_api_url,
|
|
793
|
+
"r2_bucket": s.r2_bucket,
|
|
794
|
+
"r2_index_prefix": s.r2_index_prefix,
|
|
795
|
+
"r2_contribution_prefix": s.r2_contribution_prefix,
|
|
796
|
+
"r2_seed_prefix": s.r2_seed_prefix,
|
|
584
797
|
"app_home": str(s.app_home),
|
|
585
798
|
}
|
|
586
799
|
|
|
@@ -596,19 +809,25 @@ def public_settings_text(settings: Settings | None = None) -> str:
|
|
|
596
809
|
_readiness_line("Apprentice Agent Status", data["apprentice_agent_status"], data.get("apprentice_agent_status_reason")),
|
|
597
810
|
f"Mentor Model Provider: {provider}",
|
|
598
811
|
_readiness_line("Mentor Model Provider Status", data["mentor_model_provider_status"], data.get("mentor_model_provider_status_reason")),
|
|
599
|
-
f"
|
|
812
|
+
f"Apprenticeship Mode: {apprenticeship_mode_display(data['apprenticeship_mode'])}",
|
|
600
813
|
f"Sensitive Info Masking: {data['sensitive_info_masking']}",
|
|
601
814
|
f"Maximum Improvement Loops: {data['max_improvement_loops']}",
|
|
602
815
|
f"Public Ecosystem Repo: {data['ecosystem_repo'] or DEFAULT_PUBLIC_ECOSYSTEM_REPO}",
|
|
603
816
|
*([f"Public Ecosystem Repo Path: {data['ecosystem_repo_path']}"] if data.get("ecosystem_repo_path") else []),
|
|
604
|
-
f"
|
|
817
|
+
f"Storage backend: {data['ecosystem_storage_backend']}",
|
|
818
|
+
f"R2 ingestion API: {data['r2_api_url'] or 'not configured'}",
|
|
819
|
+
f"R2 bucket: {data['r2_bucket']}",
|
|
820
|
+
f"R2 index prefix: {data['r2_index_prefix']}",
|
|
821
|
+
f"R2 contribution prefix: {data['r2_contribution_prefix']}",
|
|
822
|
+
f"R2 seed prefix: {data['r2_seed_prefix']}",
|
|
823
|
+
f"Agent Training Contribution Mode: {training_contribution_mode_display(data['training_contribution_mode'])}",
|
|
605
824
|
f"App Home: {data['app_home']}",
|
|
606
825
|
]
|
|
607
|
-
if s.
|
|
826
|
+
if s.apprenticeship_mode == "autonomous" and not configured_model_provider_ready(s):
|
|
608
827
|
lines.extend(
|
|
609
828
|
[
|
|
610
829
|
"",
|
|
611
|
-
"
|
|
830
|
+
"Autonomous Apprenticeship needs a ready Mentor Model Provider.",
|
|
612
831
|
"Run: apprentice configure model",
|
|
613
832
|
]
|
|
614
833
|
)
|