abstractagent 0.2.0__py3-none-any.whl → 0.3.1__py3-none-any.whl

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.
@@ -0,0 +1,82 @@
1
+ """Helpers for consistent generation params in AbstractAgent adapters.
2
+
3
+ These adapters build `EffectType.LLM_CALL` payloads for AbstractRuntime. We want
4
+ to expose a uniform `(temperature, seed)` interface across agents while keeping
5
+ backward compatibility with older runs that may not have these keys in
6
+ `vars["_runtime"]`.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Dict, Optional
12
+
13
+
14
+ def normalize_seed(seed: Any) -> Optional[int]:
15
+ """Return a provider-ready seed or None when unset/random.
16
+
17
+ Policy:
18
+ - None or any negative value -> None (meaning: do not send seed).
19
+ - bool values are ignored (JSON booleans are ints in Python).
20
+ - numeric-ish values -> int(seed) if >= 0.
21
+ """
22
+ try:
23
+ if seed is None or isinstance(seed, bool):
24
+ return None
25
+ seed_i = int(seed)
26
+ return seed_i if seed_i >= 0 else None
27
+ except Exception:
28
+ return None
29
+
30
+
31
+ def runtime_llm_params(
32
+ runtime_ns: Dict[str, Any],
33
+ *,
34
+ extra: Optional[Dict[str, Any]] = None,
35
+ default_temperature: float = 0.7,
36
+ ) -> Dict[str, Any]:
37
+ """Merge `runtime_ns` sampling controls into an LLM_CALL params dict.
38
+
39
+ Precedence:
40
+ 1) `runtime_ns.temperature` / `runtime_ns.seed` when present
41
+ 2) `extra.temperature` / `extra.seed` (step-specific defaults)
42
+ 3) `default_temperature` (only for temperature)
43
+ """
44
+ out: Dict[str, Any] = dict(extra or {})
45
+
46
+ # Temperature: always provide a float (provider-agnostic).
47
+ temp_val = runtime_ns.get("temperature") if isinstance(runtime_ns, dict) else None
48
+ if temp_val is None:
49
+ temp_val = out.get("temperature")
50
+ if temp_val is None:
51
+ temp_val = default_temperature
52
+ try:
53
+ out["temperature"] = float(temp_val)
54
+ except Exception:
55
+ out["temperature"] = float(default_temperature)
56
+
57
+ # Seed: only include when explicitly set (>= 0).
58
+ seed_val = runtime_ns.get("seed") if isinstance(runtime_ns, dict) else None
59
+ if seed_val is None:
60
+ seed_val = out.get("seed")
61
+ seed_norm = normalize_seed(seed_val)
62
+ if seed_norm is not None:
63
+ out["seed"] = seed_norm
64
+ else:
65
+ out.pop("seed", None)
66
+
67
+ # Pass-through media policies (runtime-owned defaults).
68
+ #
69
+ # This keeps thin clients simple: they can set `_runtime.audio_policy` (and
70
+ # optional language hints) once at run start, and all LLM_CALL steps inherit it.
71
+ if isinstance(runtime_ns, dict):
72
+ audio_policy = runtime_ns.get("audio_policy")
73
+ if "audio_policy" not in out and isinstance(audio_policy, str) and audio_policy.strip():
74
+ out["audio_policy"] = audio_policy.strip()
75
+
76
+ stt_language = runtime_ns.get("stt_language")
77
+ if stt_language is None:
78
+ stt_language = runtime_ns.get("audio_language")
79
+ if "stt_language" not in out and isinstance(stt_language, str) and stt_language.strip():
80
+ out["stt_language"] = stt_language.strip()
81
+
82
+ return out
@@ -0,0 +1,45 @@
1
+ """Helpers for attachment/media plumbing in runtime-backed agents."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ def extract_media_from_context(context: Dict[str, Any]) -> Optional[List[Any]]:
9
+ """Return a normalized `media` list from a runtime `context` dict.
10
+
11
+ Supported keys (best-effort):
12
+ - `context["attachments"]`: preferred (artifact refs)
13
+ - `context["media"]`: legacy/alternate
14
+ """
15
+ raw = context.get("attachments")
16
+ if raw is None:
17
+ raw = context.get("media")
18
+
19
+ if isinstance(raw, tuple):
20
+ items = list(raw)
21
+ else:
22
+ items = raw
23
+
24
+ if not isinstance(items, list) or not items:
25
+ return None
26
+
27
+ out: List[Any] = []
28
+ for item in items:
29
+ if isinstance(item, str):
30
+ s = item.strip()
31
+ if s:
32
+ out.append(s)
33
+ continue
34
+
35
+ if isinstance(item, dict):
36
+ # Prefer artifact refs; accept both {"$artifact": "..."} and {"artifact_id": "..."}.
37
+ aid = item.get("$artifact")
38
+ if not (isinstance(aid, str) and aid.strip()):
39
+ aid = item.get("artifact_id")
40
+ if isinstance(aid, str) and aid.strip():
41
+ out.append(dict(item))
42
+ continue
43
+
44
+ return out or None
45
+