dsh-biocore 0.1.0 → 0.1.2
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 +2 -2
- package/lib/py/bridge.py +15 -7
- package/lib/py-bridge.js +4 -3
- package/package.json +3 -2
- package/python/biocore_memory/__init__.py +21 -0
- package/python/biocore_memory/adapters/__init__.py +2 -0
- package/python/biocore_memory/adapters/astrbot.py +24 -0
- package/python/biocore_memory/adapters/dsh_cli.py +335 -0
- package/python/biocore_memory/co_recall.py +324 -0
- package/python/biocore_memory/consolidate/__init__.py +11 -0
- package/python/biocore_memory/consolidate/gated.py +104 -0
- package/python/biocore_memory/consolidate/neighbors.py +68 -0
- package/python/biocore_memory/consolidate/reflection.py +45 -0
- package/python/biocore_memory/consolidate/tree.py +95 -0
- package/python/biocore_memory/consolidate/writeback.py +181 -0
- package/python/biocore_memory/core/__init__.py +4 -0
- package/python/biocore_memory/core/config.py +127 -0
- package/python/biocore_memory/core/permissions.py +69 -0
- package/python/biocore_memory/core/types.py +116 -0
- package/python/biocore_memory/core/util.py +26 -0
- package/python/biocore_memory/embedding_local.py +447 -0
- package/python/biocore_memory/embedding_mode.py +156 -0
- package/python/biocore_memory/engine.py +2476 -0
- package/python/biocore_memory/engine_helpers.py +266 -0
- package/python/biocore_memory/event/__init__.py +3 -0
- package/python/biocore_memory/event/_types.py +16 -0
- package/python/biocore_memory/event/consistency.py +117 -0
- package/python/biocore_memory/event/extract.py +48 -0
- package/python/biocore_memory/event/media.py +111 -0
- package/python/biocore_memory/event/notes.py +85 -0
- package/python/biocore_memory/event/notes_link.py +87 -0
- package/python/biocore_memory/event/vector.py +69 -0
- package/python/biocore_memory/evict/__init__.py +3 -0
- package/python/biocore_memory/evict/adaptive.py +73 -0
- package/python/biocore_memory/evict/consequence.py +58 -0
- package/python/biocore_memory/evict/heat.py +54 -0
- package/python/biocore_memory/evict/inhibition.py +105 -0
- package/python/biocore_memory/evict/policy.py +188 -0
- package/python/biocore_memory/evict/score.py +23 -0
- package/python/biocore_memory/identity/__init__.py +6 -0
- package/python/biocore_memory/identity/api.py +99 -0
- package/python/biocore_memory/identity/history.py +9 -0
- package/python/biocore_memory/identity/ledger.py +191 -0
- package/python/biocore_memory/identity/narrative.py +358 -0
- package/python/biocore_memory/identity/snapshot.py +13 -0
- package/python/biocore_memory/identity/writeback.py +61 -0
- package/python/biocore_memory/index/__init__.py +3 -0
- package/python/biocore_memory/index/cue_index.py +80 -0
- package/python/biocore_memory/index/entities.py +85 -0
- package/python/biocore_memory/index/entity_boost.py +104 -0
- package/python/biocore_memory/index/graph.py +172 -0
- package/python/biocore_memory/recall/__init__.py +5 -0
- package/python/biocore_memory/recall/api.py +65 -0
- package/python/biocore_memory/recall/bm25.py +118 -0
- package/python/biocore_memory/recall/channels.py +98 -0
- package/python/biocore_memory/recall/complexity.py +62 -0
- package/python/biocore_memory/recall/constraints.py +75 -0
- package/python/biocore_memory/recall/embedding.py +745 -0
- package/python/biocore_memory/recall/expand.py +26 -0
- package/python/biocore_memory/recall/filters.py +40 -0
- package/python/biocore_memory/recall/fusion.py +18 -0
- package/python/biocore_memory/recall/mmr.py +70 -0
- package/python/biocore_memory/recall/ppr.py +85 -0
- package/python/biocore_memory/recall/retrieval_practice.py +102 -0
- package/python/biocore_memory/relay/__init__.py +2 -0
- package/python/biocore_memory/relay/card.py +51 -0
- package/python/biocore_memory/slots/__init__.py +18 -0
- package/python/biocore_memory/slots/admission.py +64 -0
- package/python/biocore_memory/slots/boundary.py +128 -0
- package/python/biocore_memory/slots/evict_bridge.py +106 -0
- package/python/biocore_memory/slots/registry.py +135 -0
- package/python/biocore_memory/slots/switch.py +42 -0
- package/python/biocore_memory/store/__init__.py +4 -0
- package/python/biocore_memory/store/audit.py +74 -0
- package/python/biocore_memory/store/compress.py +81 -0
- package/python/biocore_memory/store/dedupe.py +178 -0
- package/python/biocore_memory/store/json_store.py +154 -0
- package/python/biocore_memory/store/media.py +145 -0
- package/python/biocore_memory/store/provenance.py +73 -0
- package/python/biocore_memory/store/rate_limit.py +93 -0
- package/python/biocore_memory/store/security.py +107 -0
- package/python/biocore_memory/store/source_consistency.py +123 -0
- package/python/biocore_memory/store/tiering.py +61 -0
- package/python/biocore_memory/store/tiering_exec.py +50 -0
- package/python/biocore_memory/store/tombstone.py +23 -0
- package/python/biocore_memory/store/versions.py +69 -0
- package/python/biocore_memory/thread/__init__.py +2 -0
- package/python/biocore_memory/thread/card.py +58 -0
- package/python/biocore_model/__init__.py +37 -0
- package/python/biocore_model/affective_labor.py +162 -0
- package/python/biocore_model/appraisal.py +257 -0
- package/python/biocore_model/appraisal_action.py +78 -0
- package/python/biocore_model/archive_queue.py +60 -0
- package/python/biocore_model/attachment_behavior.py +130 -0
- package/python/biocore_model/attachment_regulation.py +75 -0
- package/python/biocore_model/attachment_state.py +41 -0
- package/python/biocore_model/attribution.py +73 -0
- package/python/biocore_model/attributor.py +162 -0
- package/python/biocore_model/autonomic.py +91 -0
- package/python/biocore_model/autonomy_affect.py +51 -0
- package/python/biocore_model/autonomy_check.py +67 -0
- package/python/biocore_model/autonomy_loop.py +122 -0
- package/python/biocore_model/autonomy_mode.py +114 -0
- package/python/biocore_model/autonomy_model.py +733 -0
- package/python/biocore_model/autonomy_params.py +131 -0
- package/python/biocore_model/autonomy_reason.py +73 -0
- package/python/biocore_model/autonomy_tick.py +227 -0
- package/python/biocore_model/bio_appraisal.py +49 -0
- package/python/biocore_model/bio_autonomy_state.py +171 -0
- package/python/biocore_model/bio_config.py +221 -0
- package/python/biocore_model/bio_const.py +128 -0
- package/python/biocore_model/bio_daily.py +267 -0
- package/python/biocore_model/bio_emotion.py +538 -0
- package/python/biocore_model/bio_emotion2.py +214 -0
- package/python/biocore_model/bio_goal.py +220 -0
- package/python/biocore_model/bio_identity.py +82 -0
- package/python/biocore_model/bio_noise.py +119 -0
- package/python/biocore_model/bio_physiology2.py +114 -0
- package/python/biocore_model/bio_snapshot.py +324 -0
- package/python/biocore_model/bio_state.py +272 -0
- package/python/biocore_model/bio_tick.py +310 -0
- package/python/biocore_model/bio_util.py +82 -0
- package/python/biocore_model/blocks.py +264 -0
- package/python/biocore_model/boundary.py +251 -0
- package/python/biocore_model/boundary_gate.py +188 -0
- package/python/biocore_model/commitment_extractor.py +517 -0
- package/python/biocore_model/compassion_fatigue.py +84 -0
- package/python/biocore_model/connection_bids.py +120 -0
- package/python/biocore_model/core_bridge.py +177 -0
- package/python/biocore_model/core_client.py +127 -0
- package/python/biocore_model/core_commands.py +112 -0
- package/python/biocore_model/core_mode.py +104 -0
- package/python/biocore_model/core_mode_ui.mjs +104 -0
- package/python/biocore_model/criticality.py +81 -0
- package/python/biocore_model/defense_mechanisms.py +272 -0
- package/python/biocore_model/delta_budget.py +99 -0
- package/python/biocore_model/diag_trace.py +274 -0
- package/python/biocore_model/dissonance.py +134 -0
- package/python/biocore_model/emotion_geometry.py +108 -0
- package/python/biocore_model/emotion_probe.py +209 -0
- package/python/biocore_model/entity_graph.py +931 -0
- package/python/biocore_model/entity_resolve.py +260 -0
- package/python/biocore_model/envy.py +193 -0
- package/python/biocore_model/exit_or_silence.py +230 -0
- package/python/biocore_model/expr_guard.py +24 -0
- package/python/biocore_model/expr_intent.py +77 -0
- package/python/biocore_model/expr_state.py +204 -0
- package/python/biocore_model/expr_template.py +105 -0
- package/python/biocore_model/expr_tone.py +81 -0
- package/python/biocore_model/extreme_scenarios.py +205 -0
- package/python/biocore_model/feedback_flow.py +227 -0
- package/python/biocore_model/feedback_guard.py +129 -0
- package/python/biocore_model/feedback_llm.py +163 -0
- package/python/biocore_model/feedback_memory.py +96 -0
- package/python/biocore_model/feedback_user.py +93 -0
- package/python/biocore_model/frustration_curve.py +110 -0
- package/python/biocore_model/granularity.py +283 -0
- package/python/biocore_model/graph_extract.py +248 -0
- package/python/biocore_model/graph_recall.py +221 -0
- package/python/biocore_model/intent_render.py +91 -0
- package/python/biocore_model/intero_core.py +235 -0
- package/python/biocore_model/intero_style.py +116 -0
- package/python/biocore_model/layered_memory.py +297 -0
- package/python/biocore_model/learning_probe.py +120 -0
- package/python/biocore_model/memory_dual.py +224 -0
- package/python/biocore_model/memory_forgetting.py +125 -0
- package/python/biocore_model/memory_store.py +1399 -0
- package/python/biocore_model/metacog.py +153 -0
- package/python/biocore_model/migrate.py +733 -0
- package/python/biocore_model/migrate_store.py +337 -0
- package/python/biocore_model/mind_wander.py +111 -0
- package/python/biocore_model/mood.py +48 -0
- package/python/biocore_model/narrative.py +172 -0
- package/python/biocore_model/needs_esteem.py +116 -0
- package/python/biocore_model/needs_events.py +137 -0
- package/python/biocore_model/needs_sleep.py +72 -0
- package/python/biocore_model/noise_bank.py +95 -0
- package/python/biocore_model/persona_flow.mjs +25 -0
- package/python/biocore_model/pipeline.py +240 -0
- package/python/biocore_model/pipeline_api.py +200 -0
- package/python/biocore_model/plugin_config.py +83 -0
- package/python/biocore_model/plugin_routes.py +1435 -0
- package/python/biocore_model/policy_learning.py +132 -0
- package/python/biocore_model/possible_selves.py +110 -0
- package/python/biocore_model/predictor.py +178 -0
- package/python/biocore_model/preset.py +205 -0
- package/python/biocore_model/proactive_context.py +153 -0
- package/python/biocore_model/prompt_rules.py +90 -0
- package/python/biocore_model/prospective.py +183 -0
- package/python/biocore_model/provider_fallback.py +97 -0
- package/python/biocore_model/reconstruction.py +132 -0
- package/python/biocore_model/regulation_loop.py +179 -0
- package/python/biocore_model/regulation_strategies.py +294 -0
- package/python/biocore_model/relation_stage.py +130 -0
- package/python/biocore_model/relationship_stage.py +95 -0
- package/python/biocore_model/render.py +901 -0
- package/python/biocore_model/render_guard.mjs +34 -0
- package/python/biocore_model/repair_after_boundary.py +350 -0
- package/python/biocore_model/reply_limit.py +183 -0
- package/python/biocore_model/reply_split.py +203 -0
- package/python/biocore_model/rollback.py +143 -0
- package/python/biocore_model/runtime.py +479 -0
- package/python/biocore_model/sanitize.py +200 -0
- package/python/biocore_model/scheduler.py +123 -0
- package/python/biocore_model/schema.py +120 -0
- package/python/biocore_model/secrecy.py +145 -0
- package/python/biocore_model/self_esteem.py +50 -0
- package/python/biocore_model/self_intent.py +437 -0
- package/python/biocore_model/self_interest.py +263 -0
- package/python/biocore_model/self_verification.py +178 -0
- package/python/biocore_model/services.py +78 -0
- package/python/biocore_model/situation.py +254 -0
- package/python/biocore_model/sleep_circadian.py +116 -0
- package/python/biocore_model/social_pain.py +69 -0
- package/python/biocore_model/social_repair.py +111 -0
- package/python/biocore_model/social_theory.py +131 -0
- package/python/biocore_model/source_monitoring.py +292 -0
- package/python/biocore_model/stages.py +487 -0
- package/python/biocore_model/state_tag.py +231 -0
- package/python/biocore_model/switch_groups.mjs +201 -0
- package/python/biocore_model/tabs_state.mjs +37 -0
- package/python/biocore_model/template_expr.py +252 -0
- package/python/biocore_model/tools/caps_check.mjs +23 -0
- package/python/biocore_model/tools/init_symbols_check.mjs +11 -0
- package/python/biocore_model/tools/missing_ids.mjs +16 -0
- package/python/biocore_model/tools/scope_check.mjs +19 -0
- package/python/biocore_model/topic_control.py +268 -0
- package/python/biocore_model/turn_memory.py +152 -0
- package/python/biocore_model/ui_compat.mjs +48 -0
- package/python/biocore_model/ui_settings.py +266 -0
- package/python/biocore_model/ui_settings.py.bak_authority +108 -0
- package/python/biocore_model/value_order.py +186 -0
- package/python/biocore_model/view_mode.mjs +8 -0
- package/python/biocore_model/voice_bank.py +177 -0
- package/python/biocore_model/waiting_sense.py +229 -0
- package/python/biocore_model/x_directives.py +142 -0
- package/python/biocore_runtime/__init__.py +7 -0
- package/python/biocore_runtime/pipeline.py +1915 -0
- package/python/dsh_adapter/README.md +96 -0
- package/python/dsh_adapter/adapter.py +1077 -0
- package/python/dsh_adapter/cli.py +107 -0
- package/python/dsh_adapter/data/demo_state.json +164 -0
- package/python/dsh_adapter/data/verify_state.json +164 -0
- package/python/dsh_adapter/tests/__init__.py +1 -0
- package/python/dsh_adapter/tests/test_adapter.py +494 -0
- package/ui/panel-layout.js +3 -3
- package/ui/panel.css +53 -6
- package/ui/panel.html +33 -32
- package/ui/panel.js +9 -1
- package/lib/py/__pycache__/bridge.cpython-310.pyc +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""L2 emotion probe: model-chosen feedback deltas for one reply.
|
|
3
|
+
|
|
4
|
+
Instead of asking for a label, the second tiny call asks the model what the
|
|
5
|
+
reply did to its internal state and why. The module owns the prompt, parsing and
|
|
6
|
+
ALL local protections (whitelist, per-item clamp, per-core rate limit, low
|
|
7
|
+
confidence drop). It never raises and never blocks the reply.
|
|
8
|
+
|
|
9
|
+
Contract:
|
|
10
|
+
{"deltas": {"v": -0.3, "a": 0.1}, "why": "<=30 chars", "c": 0.0-1.0}
|
|
11
|
+
|
|
12
|
+
Failures (timeout/empty/garbage/low confidence) return {}.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import json
|
|
18
|
+
import re
|
|
19
|
+
import time
|
|
20
|
+
|
|
21
|
+
try: # AstrBot requires the host logger
|
|
22
|
+
from astrbot.api import logger
|
|
23
|
+
except Exception: # pragma: no cover - offline tests
|
|
24
|
+
class _NullLogger: # offline fallback: never imports stdlib logging
|
|
25
|
+
def _noop(self, *args, **kwargs):
|
|
26
|
+
return None
|
|
27
|
+
debug = info = warning = error = exception = critical = _noop
|
|
28
|
+
logger = _NullLogger()
|
|
29
|
+
|
|
30
|
+
PROBE_TIMEOUT = 3.0
|
|
31
|
+
PROBE_MIN_CONFIDENCE = 0.4
|
|
32
|
+
DELTA_FIELDS = ("v", "a", "d", "social", "trust", "stress", "self_esteem")
|
|
33
|
+
DELTA_CLAMP = 0.2
|
|
34
|
+
RATE_WINDOW_SECONDS = 60
|
|
35
|
+
RATE_BUDGET = 0.4
|
|
36
|
+
WHY_MAX_CHARS = 30
|
|
37
|
+
MAX_TEXT_CHARS = 160
|
|
38
|
+
MAX_USER_CHARS = 80
|
|
39
|
+
|
|
40
|
+
_INSTRUCTION = (
|
|
41
|
+
"用JSON描述内部状态影响:\n"
|
|
42
|
+
'{"deltas":{"v":-0.3},"why":"≤30字","c":0.0-1.0}\n'
|
|
43
|
+
'字段:v/a/d/social/trust/stress/self_esteem;无影响{"deltas":{}}'
|
|
44
|
+
)
|
|
45
|
+
INSTRUCTION_HINT = _INSTRUCTION
|
|
46
|
+
|
|
47
|
+
_JSON_RE = re.compile(r"\{.*\}", re.S)
|
|
48
|
+
_FENCE_RE = re.compile(r"\x60{3}(?:json)?\s*(.*?)\s*\x60{3}", re.S | re.I)
|
|
49
|
+
_RATE_STATE = {}
|
|
50
|
+
_FEEDBACK_FIELDS = {
|
|
51
|
+
"v": "valence_delta", "a": "arousal_delta", "d": "dominance_delta",
|
|
52
|
+
"social": "social_delta", "trust": "trust_delta",
|
|
53
|
+
"stress": "stress_delta", "self_esteem": "self_esteem_delta",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _log_raw(raw):
|
|
58
|
+
"""Diagnostic only: never alters behaviour, never raises."""
|
|
59
|
+
try:
|
|
60
|
+
logger.info("[biocore] emotion probe raw=%r", str(raw or "")[:200])
|
|
61
|
+
except Exception:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _num(value, default=None):
|
|
66
|
+
try:
|
|
67
|
+
return float(value)
|
|
68
|
+
except Exception:
|
|
69
|
+
return default
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _clamp(value, low=0.0, high=1.0):
|
|
73
|
+
try:
|
|
74
|
+
return max(low, min(high, float(value)))
|
|
75
|
+
except Exception:
|
|
76
|
+
return low
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def reset_rate():
|
|
80
|
+
"""Clear the per-core rate window (tests / manual reset)."""
|
|
81
|
+
_RATE_STATE.clear()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def build_prompt(text, last_user_msg="") -> str:
|
|
85
|
+
return (_INSTRUCTION + "\n对方刚说:" + str(last_user_msg or "")[:MAX_USER_CHARS]
|
|
86
|
+
+ "\n回复:" + str(text or "")[:MAX_TEXT_CHARS])
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _parse_payload(raw):
|
|
90
|
+
body = str(raw or "").strip()
|
|
91
|
+
if not body:
|
|
92
|
+
return None
|
|
93
|
+
fence = _FENCE_RE.search(body)
|
|
94
|
+
if fence:
|
|
95
|
+
body = fence.group(1).strip()
|
|
96
|
+
for candidate in _JSON_RE.findall(body):
|
|
97
|
+
try:
|
|
98
|
+
data = json.loads(candidate)
|
|
99
|
+
except Exception:
|
|
100
|
+
repaired = re.sub(r",\s*([}\]])", r"\1", candidate)
|
|
101
|
+
try:
|
|
102
|
+
data = json.loads(repaired)
|
|
103
|
+
except Exception:
|
|
104
|
+
continue
|
|
105
|
+
if isinstance(data, dict):
|
|
106
|
+
return data
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _rate_limit(core, now, deltas):
|
|
111
|
+
"""Same core / same minute: cumulative |delta| <= RATE_BUDGET, scale down."""
|
|
112
|
+
stamp = _num(now, time.time())
|
|
113
|
+
window = int(stamp // RATE_WINDOW_SECONDS)
|
|
114
|
+
key = str(id(core)) if core is not None else "global"
|
|
115
|
+
slot = _RATE_STATE.get(key)
|
|
116
|
+
if not isinstance(slot, dict) or int(slot.get("window", -1)) != window:
|
|
117
|
+
slot = {"window": window, "used": 0.0}
|
|
118
|
+
_RATE_STATE[key] = slot
|
|
119
|
+
used = _num(slot.get("used"), 0.0)
|
|
120
|
+
remaining = max(0.0, RATE_BUDGET - used)
|
|
121
|
+
total = sum(abs(v) for v in deltas.values())
|
|
122
|
+
if total > remaining:
|
|
123
|
+
scale = (remaining / total) if total > 0 else 0.0
|
|
124
|
+
deltas = {key: round(value * scale, 4) for key, value in deltas.items()
|
|
125
|
+
if abs(value * scale) > 1e-9}
|
|
126
|
+
slot["used"] = round(used + sum(abs(v) for v in deltas.values()), 4)
|
|
127
|
+
return deltas
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def parse(raw, core=None, now=None):
|
|
131
|
+
"""Parse one probe response with local protections; {} on any failure."""
|
|
132
|
+
try:
|
|
133
|
+
data = _parse_payload(raw)
|
|
134
|
+
if not isinstance(data, dict):
|
|
135
|
+
_log_raw(raw)
|
|
136
|
+
return {}
|
|
137
|
+
confidence = _num(data.get("c", data.get("confidence")), 0.0)
|
|
138
|
+
if confidence < PROBE_MIN_CONFIDENCE:
|
|
139
|
+
_log_raw(raw)
|
|
140
|
+
return {}
|
|
141
|
+
raw_deltas = data.get("deltas")
|
|
142
|
+
deltas = {}
|
|
143
|
+
if isinstance(raw_deltas, dict):
|
|
144
|
+
for field, value in raw_deltas.items():
|
|
145
|
+
if field not in DELTA_FIELDS:
|
|
146
|
+
continue
|
|
147
|
+
number = _num(value)
|
|
148
|
+
if number is None:
|
|
149
|
+
continue
|
|
150
|
+
number = max(-DELTA_CLAMP, min(DELTA_CLAMP, number))
|
|
151
|
+
if abs(number) < 1e-9:
|
|
152
|
+
continue
|
|
153
|
+
deltas[field] = round(number, 4)
|
|
154
|
+
if deltas:
|
|
155
|
+
deltas = _rate_limit(core, now, deltas)
|
|
156
|
+
why = str(data.get("why") or "").strip()[:WHY_MAX_CHARS]
|
|
157
|
+
return {"deltas": deltas, "why": why,
|
|
158
|
+
"confidence": round(_clamp(confidence), 3), "source": "probe"}
|
|
159
|
+
except Exception:
|
|
160
|
+
return {}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
async def probe(text, last_user_msg, llm_call, timeout=None,
|
|
164
|
+
core=None, now=None):
|
|
165
|
+
"""One tiny async probe; {} on timeout/empty/garbage/error (never raises).
|
|
166
|
+
|
|
167
|
+
timeout=None means no probe-level deadline: the provider layer owns the
|
|
168
|
+
only timeout (main passes an explicit provider timeout).
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
prompt = build_prompt(text, last_user_msg)
|
|
172
|
+
_call = llm_call(prompt)
|
|
173
|
+
if timeout is None:
|
|
174
|
+
raw = await _call
|
|
175
|
+
else:
|
|
176
|
+
raw = await asyncio.wait_for(_call, timeout=max(0.05, float(timeout)))
|
|
177
|
+
if raw is None:
|
|
178
|
+
_log_raw(raw)
|
|
179
|
+
return {}
|
|
180
|
+
if not isinstance(raw, str):
|
|
181
|
+
raw = str(getattr(raw, "completion_text", "") or "")
|
|
182
|
+
return parse(raw, core=core, now=now)
|
|
183
|
+
except asyncio.TimeoutError:
|
|
184
|
+
return {}
|
|
185
|
+
except Exception:
|
|
186
|
+
return {}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def to_feedback_payload(result):
|
|
190
|
+
"""Probe result -> feedback_llm inferred payload (expanded *_delta keys)."""
|
|
191
|
+
if not isinstance(result, dict):
|
|
192
|
+
return {}
|
|
193
|
+
deltas = result.get("deltas")
|
|
194
|
+
if not isinstance(deltas, dict) or not deltas:
|
|
195
|
+
return {}
|
|
196
|
+
payload = {}
|
|
197
|
+
for field, value in deltas.items():
|
|
198
|
+
key = _FEEDBACK_FIELDS.get(field)
|
|
199
|
+
if not key:
|
|
200
|
+
continue
|
|
201
|
+
number = _num(value)
|
|
202
|
+
if number is None:
|
|
203
|
+
continue
|
|
204
|
+
payload[key] = round(number, 4)
|
|
205
|
+
if not payload:
|
|
206
|
+
return {}
|
|
207
|
+
payload["confidence"] = round(_clamp(result.get("confidence", 0.0)), 3)
|
|
208
|
+
payload["source"] = "probe"
|
|
209
|
+
return payload
|