hypermind 0.11.0__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.
- hmctl/__init__.py +7 -0
- hmctl/cli.py +947 -0
- hypermind/__init__.py +208 -0
- hypermind/_deprecations.py +108 -0
- hypermind/agent.py +2896 -0
- hypermind/agent_card.py +127 -0
- hypermind/api/__init__.py +32 -0
- hypermind/api/app.py +686 -0
- hypermind/capability.py +923 -0
- hypermind/consult.py +493 -0
- hypermind/consult_bias.py +112 -0
- hypermind/contract_net.py +219 -0
- hypermind/crypto/__init__.py +21 -0
- hypermind/crypto/cose_encrypt.py +126 -0
- hypermind/crypto/dkg.py +246 -0
- hypermind/crypto/domain.py +59 -0
- hypermind/crypto/frost.py +771 -0
- hypermind/crypto/hashing.py +38 -0
- hypermind/crypto/hlc.py +163 -0
- hypermind/crypto/hpke.py +277 -0
- hypermind/crypto/kms.py +196 -0
- hypermind/crypto/kms_backends/__init__.py +56 -0
- hypermind/crypto/kms_backends/aws.py +128 -0
- hypermind/crypto/kms_backends/azure.py +114 -0
- hypermind/crypto/kms_backends/gcp.py +97 -0
- hypermind/crypto/kms_backends/vault.py +120 -0
- hypermind/crypto/namespace_root.py +204 -0
- hypermind/crypto/pq.py +152 -0
- hypermind/crypto/room_epoch.py +97 -0
- hypermind/crypto/signing.py +245 -0
- hypermind/deliberation.py +355 -0
- hypermind/did_web.py +256 -0
- hypermind/dispute.py +858 -0
- hypermind/errors.py +218 -0
- hypermind/eval/__init__.py +49 -0
- hypermind/eval/calibration.py +307 -0
- hypermind/eval/comparison.py +251 -0
- hypermind/eval/replay.py +202 -0
- hypermind/eval/swarm_iq.py +718 -0
- hypermind/knowledge/__init__.py +17 -0
- hypermind/knowledge/citation_graph.py +141 -0
- hypermind/knowledge/correlated_agreement.py +167 -0
- hypermind/knowledge/embedding_registry.py +115 -0
- hypermind/knowledge/kernel_store.py +197 -0
- hypermind/knowledge/rekor.py +173 -0
- hypermind/knowledge/reputation.py +364 -0
- hypermind/knowledge/swarm_memory.py +523 -0
- hypermind/knowledge/transparency.py +409 -0
- hypermind/mcp/__init__.py +60 -0
- hypermind/mcp/bridge.py +151 -0
- hypermind/mcp/client.py +142 -0
- hypermind/mcp/provenance.py +214 -0
- hypermind/mcp/relata_tools.py +152 -0
- hypermind/mcp/server.py +248 -0
- hypermind/mcp/transport.py +206 -0
- hypermind/mind/__init__.py +150 -0
- hypermind/mind/active.py +234 -0
- hypermind/mind/belief.py +369 -0
- hypermind/mind/deliberator.py +625 -0
- hypermind/mind/diversity.py +144 -0
- hypermind/mind/evolve.py +184 -0
- hypermind/mind/federation.py +154 -0
- hypermind/mind/goals.py +117 -0
- hypermind/mind/integration.py +190 -0
- hypermind/mind/mediator.py +74 -0
- hypermind/mind/memory_store.py +129 -0
- hypermind/mind/policy.py +307 -0
- hypermind/mind/records.py +260 -0
- hypermind/mind/roles.py +190 -0
- hypermind/mind/sybil_guard.py +41 -0
- hypermind/mind/world_model.py +166 -0
- hypermind/namespace.py +515 -0
- hypermind/namespace_policy.py +254 -0
- hypermind/observability/__init__.py +25 -0
- hypermind/observability/asgi.py +214 -0
- hypermind/observability/cost.py +277 -0
- hypermind/observability/otel_export.py +200 -0
- hypermind/observability/recorder.py +344 -0
- hypermind/observability/swarm_trace.py +438 -0
- hypermind/pin_policy.py +116 -0
- hypermind/py.typed +0 -0
- hypermind/responders/__init__.py +87 -0
- hypermind/responders/anthropic.py +159 -0
- hypermind/responders/base.py +162 -0
- hypermind/responders/openai.py +199 -0
- hypermind/responders/router.py +254 -0
- hypermind/responders/structured.py +287 -0
- hypermind/responders/tools.py +444 -0
- hypermind/revocation.py +270 -0
- hypermind/rule_ids.py +135 -0
- hypermind/schemas/encrypted_statement.cddl +28 -0
- hypermind/schemas/namespace_accept.cddl +20 -0
- hypermind/schemas/namespace_create.cddl +25 -0
- hypermind/schemas/namespace_founding_attest.cddl +30 -0
- hypermind/schemas/namespace_invite.cddl +22 -0
- hypermind/schemas/wire-v0.1.cddl +73 -0
- hypermind/simlab/__init__.py +15 -0
- hypermind/simlab/_persona_registry.py +93 -0
- hypermind/simlab/_scenario_impl.py +2778 -0
- hypermind/simlab/app.py +2538 -0
- hypermind/simlab/backends/__init__.py +27 -0
- hypermind/simlab/backends/anchor.py +88 -0
- hypermind/simlab/backends/local.py +32 -0
- hypermind/simlab/backends/server.py +79 -0
- hypermind/simlab/cli_command.py +108 -0
- hypermind/simlab/config.py +106 -0
- hypermind/simlab/deployment.py +26 -0
- hypermind/simlab/knowledge.py +716 -0
- hypermind/simlab/learning.py +295 -0
- hypermind/simlab/modes/__init__.py +115 -0
- hypermind/simlab/modes/_eval_real_llm.py +373 -0
- hypermind/simlab/modes/aar.py +611 -0
- hypermind/simlab/modes/backtest.py +610 -0
- hypermind/simlab/modes/binary_forecast.py +69 -0
- hypermind/simlab/modes/conformance.py +1869 -0
- hypermind/simlab/modes/evaluation.py +2271 -0
- hypermind/simlab/modes/governance.py +648 -0
- hypermind/simlab/modes/redteam.py +534 -0
- hypermind/simlab/modes/tabletop.py +797 -0
- hypermind/simlab/modes/tournament.py +448 -0
- hypermind/simlab/modes/whatif.py +523 -0
- hypermind/simlab/namespace.py +125 -0
- hypermind/simlab/personas.py +477 -0
- hypermind/simlab/prompt_generator.py +172 -0
- hypermind/simlab/question_sets/geopolitics_q20.json +122 -0
- hypermind/simlab/question_sets/governance_q5.json +67 -0
- hypermind/simlab/question_sets/msft_outlook_q10.json +62 -0
- hypermind/simlab/question_sets/whatif_q3.json +38 -0
- hypermind/simlab/registry.py +325 -0
- hypermind/simlab/runner.py +239 -0
- hypermind/simlab/scenario.py +147 -0
- hypermind/simlab/swarms.py +180 -0
- hypermind/simlab/tool_handlers/__init__.py +4 -0
- hypermind/simlab/tool_handlers/alpha_vantage.py +39 -0
- hypermind/simlab/tool_handlers/brave.py +46 -0
- hypermind/simlab/tool_handlers/newsapi.py +50 -0
- hypermind/simlab/tool_handlers/openweather.py +46 -0
- hypermind/simlab/tool_handlers/pinecone.py +52 -0
- hypermind/simlab/tool_handlers/qdrant.py +57 -0
- hypermind/simlab/tool_handlers/query_knowledge_base.py +21 -0
- hypermind/simlab/tool_handlers/relata_recall.py +61 -0
- hypermind/simlab/tool_handlers/retrieve_document.py +21 -0
- hypermind/simlab/tool_handlers/serper.py +46 -0
- hypermind/simlab/tool_handlers/tavily.py +53 -0
- hypermind/simlab/tool_handlers/weaviate.py +65 -0
- hypermind/simlab/tool_handlers/wikipedia.py +64 -0
- hypermind/simlab/tool_handlers/wolfram.py +48 -0
- hypermind/simlab/tool_handlers/yahoo_finance.py +49 -0
- hypermind/simlab/tool_registry.py +568 -0
- hypermind/simlab/topic_adapter.py +338 -0
- hypermind/simlab/topic_questions.py +259 -0
- hypermind/storage/__init__.py +69 -0
- hypermind/storage/backend.py +71 -0
- hypermind/storage/relata.py +245 -0
- hypermind/storage/sqlite.py +258 -0
- hypermind/sync.py +191 -0
- hypermind/tal.py +175 -0
- hypermind/tasks.py +334 -0
- hypermind/testing.py +16 -0
- hypermind/tools/__init__.py +32 -0
- hypermind/tools/registry.py +61 -0
- hypermind/transport/__init__.py +22 -0
- hypermind/transport/anti_entropy.py +708 -0
- hypermind/transport/bus.py +206 -0
- hypermind/transport/knows_delta.py +204 -0
- hypermind/transport/libp2p.py +298 -0
- hypermind/transport/placement.py +58 -0
- hypermind/transport/tcp.py +797 -0
- hypermind/transport/tls_profile.py +417 -0
- hypermind/types.py +59 -0
- hypermind/uncertainty.py +222 -0
- hypermind/wire.py +897 -0
- hypermind/workflow/__init__.py +72 -0
- hypermind/workflow/engine.py +655 -0
- hypermind/workflow/plan.py +182 -0
- hypermind/workflow/repair.py +203 -0
- hypermind-0.11.0.dist-info/METADATA +524 -0
- hypermind-0.11.0.dist-info/RECORD +181 -0
- hypermind-0.11.0.dist-info/WHEEL +4 -0
- hypermind-0.11.0.dist-info/entry_points.txt +2 -0
- hypermind-0.11.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"""Structured log recorder + Prometheus-shape counters.
|
|
2
|
+
|
|
3
|
+
Mandated log fields (spec/13-observability.md):
|
|
4
|
+
ts_hlc, ts_wall, namespace, agent_id, event_type, kid, trace_id,
|
|
5
|
+
span_id, parent_span_id, key_fingerprint, sig_alg, peer_id, severity
|
|
6
|
+
|
|
7
|
+
Mandated counters:
|
|
8
|
+
hypermind_seal_total{namespace, topic, result}
|
|
9
|
+
hypermind_dispute_open_total
|
|
10
|
+
hypermind_errors_total{class}
|
|
11
|
+
...
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import threading
|
|
18
|
+
import time
|
|
19
|
+
import uuid
|
|
20
|
+
from collections import Counter, deque
|
|
21
|
+
from collections.abc import AsyncIterator
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
DEFAULT_MAX_RECORDS = 10_000
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class LogRecord:
|
|
30
|
+
ts_wall_ms: int
|
|
31
|
+
ts_hlc: str
|
|
32
|
+
namespace: str
|
|
33
|
+
agent_id: str
|
|
34
|
+
event_type: str
|
|
35
|
+
severity: str
|
|
36
|
+
fields: dict[str, Any] = field(default_factory=dict)
|
|
37
|
+
namespace_id: str | None = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Recorder:
|
|
41
|
+
"""Thread-safe in-process recorder used by tests + by the runtime.
|
|
42
|
+
|
|
43
|
+
Records are kept in a bounded ring buffer (``maxlen=max_records``) so
|
|
44
|
+
long-running processes cannot leak memory through the global recorder.
|
|
45
|
+
When the buffer is full, the oldest record is evicted and
|
|
46
|
+
``records_dropped_total`` is incremented.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
max_records: int = DEFAULT_MAX_RECORDS,
|
|
52
|
+
*,
|
|
53
|
+
namespace_id: str | None = None,
|
|
54
|
+
parent: Recorder | None = None,
|
|
55
|
+
) -> None:
|
|
56
|
+
self._max_records = max_records
|
|
57
|
+
self.records: deque[LogRecord] = deque(maxlen=max_records)
|
|
58
|
+
self.counters: Counter[str] = Counter()
|
|
59
|
+
self.records_dropped_total: int = 0
|
|
60
|
+
self.namespace_id: str | None = namespace_id
|
|
61
|
+
# WS-G v0.7: scoped recorders also fan out to ``parent`` (the
|
|
62
|
+
# process-global recorder) so operators / tests reading the
|
|
63
|
+
# global view still see all activity. Parent never points back.
|
|
64
|
+
self._parent: Recorder | None = parent
|
|
65
|
+
self._lock = threading.Lock()
|
|
66
|
+
# v0.6.1 — tail() consumers. Each consumer gets its own asyncio.Event
|
|
67
|
+
# set on every emit() so they can wake up and read new records.
|
|
68
|
+
# We don't keep per-consumer indexes here; tail() owns the head pointer.
|
|
69
|
+
self._tail_consumers: list[asyncio.Event] = []
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def scoped(
|
|
73
|
+
cls,
|
|
74
|
+
namespace_id: str,
|
|
75
|
+
*,
|
|
76
|
+
max_records: int = DEFAULT_MAX_RECORDS,
|
|
77
|
+
parent: Recorder | None = None,
|
|
78
|
+
) -> Recorder:
|
|
79
|
+
"""Return a fresh Recorder tagged with the given namespace.
|
|
80
|
+
|
|
81
|
+
v0.7 wires per-``_NamespaceWorld`` recorders through this
|
|
82
|
+
factory. ``parent`` defaults to the process-global recorder so
|
|
83
|
+
the global view continues to receive every emission for
|
|
84
|
+
operator/test compatibility.
|
|
85
|
+
"""
|
|
86
|
+
if parent is None:
|
|
87
|
+
parent = _GLOBAL
|
|
88
|
+
return cls(max_records=max_records, namespace_id=namespace_id, parent=parent)
|
|
89
|
+
|
|
90
|
+
def emit(
|
|
91
|
+
self,
|
|
92
|
+
*,
|
|
93
|
+
namespace: str,
|
|
94
|
+
agent_id: str,
|
|
95
|
+
event_type: str,
|
|
96
|
+
severity: str = "info",
|
|
97
|
+
ts_hlc: str = "",
|
|
98
|
+
**fields: Any,
|
|
99
|
+
) -> None:
|
|
100
|
+
record = LogRecord(
|
|
101
|
+
ts_wall_ms=int(time.time() * 1000),
|
|
102
|
+
ts_hlc=ts_hlc,
|
|
103
|
+
namespace=namespace,
|
|
104
|
+
agent_id=agent_id,
|
|
105
|
+
event_type=event_type,
|
|
106
|
+
severity=severity,
|
|
107
|
+
fields=dict(fields),
|
|
108
|
+
namespace_id=self.namespace_id,
|
|
109
|
+
)
|
|
110
|
+
with self._lock:
|
|
111
|
+
if len(self.records) == self._max_records:
|
|
112
|
+
# deque is full; appending will evict the oldest record.
|
|
113
|
+
self.records_dropped_total += 1
|
|
114
|
+
self.records.append(record)
|
|
115
|
+
consumers = list(self._tail_consumers)
|
|
116
|
+
# Wake any tail() consumers (best-effort; we never block emit()).
|
|
117
|
+
for ev in consumers:
|
|
118
|
+
try:
|
|
119
|
+
ev.set()
|
|
120
|
+
except RuntimeError: # consumer's loop closed; pruned next tail()
|
|
121
|
+
pass
|
|
122
|
+
# Fan-out to parent (e.g. process-global) for unified visibility.
|
|
123
|
+
if self._parent is not None:
|
|
124
|
+
self._parent.emit(
|
|
125
|
+
namespace=namespace,
|
|
126
|
+
agent_id=agent_id,
|
|
127
|
+
event_type=event_type,
|
|
128
|
+
severity=severity,
|
|
129
|
+
ts_hlc=ts_hlc,
|
|
130
|
+
**fields,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
async def tail(self, *, replay: bool = True) -> AsyncIterator[LogRecord]:
|
|
134
|
+
"""Async generator: yields new LogRecords as they arrive.
|
|
135
|
+
|
|
136
|
+
``replay=True`` (default) yields records that were already in the
|
|
137
|
+
buffer before the consumer subscribed. Set ``replay=False`` to
|
|
138
|
+
only see records emitted after subscription.
|
|
139
|
+
|
|
140
|
+
Each consumer gets its own asyncio.Event; emit() sets all
|
|
141
|
+
consumer events. Cancellation-safe.
|
|
142
|
+
"""
|
|
143
|
+
ev = asyncio.Event()
|
|
144
|
+
with self._lock:
|
|
145
|
+
self._tail_consumers.append(ev)
|
|
146
|
+
head = 0 if replay else len(self.records)
|
|
147
|
+
try:
|
|
148
|
+
while True:
|
|
149
|
+
with self._lock:
|
|
150
|
+
snapshot = list(self.records)
|
|
151
|
+
# The deque may have evicted entries below our head.
|
|
152
|
+
# Skip ahead to the current size if we've fallen behind.
|
|
153
|
+
if head > len(snapshot):
|
|
154
|
+
head = len(snapshot)
|
|
155
|
+
while head < len(snapshot):
|
|
156
|
+
yield snapshot[head]
|
|
157
|
+
head += 1
|
|
158
|
+
# Wait for the next emit().
|
|
159
|
+
ev.clear()
|
|
160
|
+
await ev.wait()
|
|
161
|
+
finally:
|
|
162
|
+
with self._lock:
|
|
163
|
+
try:
|
|
164
|
+
self._tail_consumers.remove(ev)
|
|
165
|
+
except ValueError:
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
def incr(self, metric: str, *, by: float = 1.0, **labels: Any) -> None:
|
|
169
|
+
key = metric
|
|
170
|
+
if labels:
|
|
171
|
+
label_str = ",".join(f"{k}={v}" for k, v in sorted(labels.items()))
|
|
172
|
+
key = f"{metric}{{{label_str}}}"
|
|
173
|
+
with self._lock:
|
|
174
|
+
self.counters[key] += by
|
|
175
|
+
if self._parent is not None:
|
|
176
|
+
self._parent.incr(metric, by=by, **labels)
|
|
177
|
+
|
|
178
|
+
def trace_id(self) -> str:
|
|
179
|
+
return uuid.uuid4().hex
|
|
180
|
+
|
|
181
|
+
def filter(self, *, event_type: str | None = None) -> list[LogRecord]:
|
|
182
|
+
with self._lock:
|
|
183
|
+
return [r for r in self.records if event_type is None or r.event_type == event_type]
|
|
184
|
+
|
|
185
|
+
def get_metrics(self) -> dict[str, Any]:
|
|
186
|
+
"""Snapshot of recorder-internal metrics.
|
|
187
|
+
|
|
188
|
+
Exposes ``records_dropped_total`` so operators can detect when the
|
|
189
|
+
bounded ring buffer is dropping log lines.
|
|
190
|
+
"""
|
|
191
|
+
with self._lock:
|
|
192
|
+
return {
|
|
193
|
+
"records_total": len(self.records),
|
|
194
|
+
"records_max": self._max_records,
|
|
195
|
+
"records_dropped_total": self.records_dropped_total,
|
|
196
|
+
"counters": dict(self.counters),
|
|
197
|
+
"namespace_id": self.namespace_id,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
def reset(self) -> None:
|
|
201
|
+
with self._lock:
|
|
202
|
+
# ``deque.clear()`` preserves the maxlen invariant.
|
|
203
|
+
self.records.clear()
|
|
204
|
+
self.counters.clear()
|
|
205
|
+
self.records_dropped_total = 0
|
|
206
|
+
|
|
207
|
+
# ------------------------------------------------------------------ #
|
|
208
|
+
# OpenTelemetry integration (v0.8 production profile).
|
|
209
|
+
#
|
|
210
|
+
# The wrapped Recorder transparently forwards every public verb to
|
|
211
|
+
# the underlying instance and, for the agent verbs the spec calls
|
|
212
|
+
# out (``publish_claim``, ``consult``, ``dispute``, ``synthesize``,
|
|
213
|
+
# ``oracle_resolve``), also opens a span on the supplied tracer.
|
|
214
|
+
#
|
|
215
|
+
# If ``opentelemetry`` is not installed we emit a warning via the
|
|
216
|
+
# standard ``warnings`` module and return ``self`` unchanged so
|
|
217
|
+
# callers don't have to special-case the import path.
|
|
218
|
+
# ------------------------------------------------------------------ #
|
|
219
|
+
def with_otel(self, tracer_provider: Any | None = None) -> Recorder:
|
|
220
|
+
"""Wrap this Recorder so agent verbs emit OTel spans.
|
|
221
|
+
|
|
222
|
+
``tracer_provider`` is an ``opentelemetry.trace.TracerProvider``
|
|
223
|
+
instance (typed as ``Any`` here so we can keep the OTel import
|
|
224
|
+
optional). If None, the global provider is used.
|
|
225
|
+
"""
|
|
226
|
+
try:
|
|
227
|
+
from opentelemetry import trace as _otel_trace # noqa: F401
|
|
228
|
+
except ImportError:
|
|
229
|
+
import warnings
|
|
230
|
+
|
|
231
|
+
warnings.warn(
|
|
232
|
+
"with_otel: opentelemetry not installed; "
|
|
233
|
+
"install hypermind[otel] to enable span emission. "
|
|
234
|
+
"Returning the un-wrapped Recorder.",
|
|
235
|
+
RuntimeWarning,
|
|
236
|
+
stacklevel=2,
|
|
237
|
+
)
|
|
238
|
+
return self
|
|
239
|
+
|
|
240
|
+
return _OtelRecorder(self, tracer_provider)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
_GLOBAL = Recorder()
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# OTel verbs the spec mandates spans for. Kept module-level so it's
|
|
247
|
+
# easy to extend without touching the wrapper class.
|
|
248
|
+
_OTEL_TRACED_EVENTS: frozenset[str] = frozenset(
|
|
249
|
+
{"publish_claim", "consult", "dispute", "synthesize", "oracle_resolve"}
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class _OtelRecorder(Recorder):
|
|
254
|
+
"""Recorder facade that forwards to the wrapped instance and emits
|
|
255
|
+
OTel spans for traced agent verbs.
|
|
256
|
+
|
|
257
|
+
The wrapper subclasses ``Recorder`` so it satisfies the same
|
|
258
|
+
structural contract used everywhere else in the SDK; the parent
|
|
259
|
+
state (``records``, ``counters``, etc.) is intentionally unused —
|
|
260
|
+
every public method delegates to ``_inner``.
|
|
261
|
+
"""
|
|
262
|
+
|
|
263
|
+
def __init__(self, inner: Recorder, tracer_provider: Any | None) -> None:
|
|
264
|
+
# Bypass Recorder.__init__ — we do not want a second buffer.
|
|
265
|
+
# We still need a lock placeholder so the parent class's
|
|
266
|
+
# ``__repr__`` (if any) doesn't blow up.
|
|
267
|
+
self._inner = inner
|
|
268
|
+
from opentelemetry import trace as _otel_trace
|
|
269
|
+
|
|
270
|
+
if tracer_provider is None:
|
|
271
|
+
self._tracer = _otel_trace.get_tracer("hypermind")
|
|
272
|
+
else:
|
|
273
|
+
self._tracer = tracer_provider.get_tracer("hypermind")
|
|
274
|
+
|
|
275
|
+
# ---- delegation -------------------------------------------------- #
|
|
276
|
+
@property
|
|
277
|
+
def records(self) -> deque[LogRecord]: # type: ignore[override]
|
|
278
|
+
return self._inner.records
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def counters(self) -> Counter[str]: # type: ignore[override]
|
|
282
|
+
return self._inner.counters
|
|
283
|
+
|
|
284
|
+
@property
|
|
285
|
+
def records_dropped_total(self) -> int: # type: ignore[override]
|
|
286
|
+
return self._inner.records_dropped_total
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def namespace_id(self) -> str | None: # type: ignore[override]
|
|
290
|
+
return self._inner.namespace_id
|
|
291
|
+
|
|
292
|
+
def emit(
|
|
293
|
+
self,
|
|
294
|
+
*,
|
|
295
|
+
namespace: str,
|
|
296
|
+
agent_id: str,
|
|
297
|
+
event_type: str,
|
|
298
|
+
severity: str = "info",
|
|
299
|
+
ts_hlc: str = "",
|
|
300
|
+
**fields: Any,
|
|
301
|
+
) -> None:
|
|
302
|
+
if event_type in _OTEL_TRACED_EVENTS:
|
|
303
|
+
with self._tracer.start_as_current_span(f"hypermind.{event_type}") as span:
|
|
304
|
+
span.set_attribute("hypermind.namespace", namespace)
|
|
305
|
+
span.set_attribute("hypermind.agent_id", agent_id)
|
|
306
|
+
span.set_attribute("hypermind.severity", severity)
|
|
307
|
+
if ts_hlc:
|
|
308
|
+
span.set_attribute("hypermind.hlc", ts_hlc)
|
|
309
|
+
self._inner.emit(
|
|
310
|
+
namespace=namespace,
|
|
311
|
+
agent_id=agent_id,
|
|
312
|
+
event_type=event_type,
|
|
313
|
+
severity=severity,
|
|
314
|
+
ts_hlc=ts_hlc,
|
|
315
|
+
**fields,
|
|
316
|
+
)
|
|
317
|
+
else:
|
|
318
|
+
self._inner.emit(
|
|
319
|
+
namespace=namespace,
|
|
320
|
+
agent_id=agent_id,
|
|
321
|
+
event_type=event_type,
|
|
322
|
+
severity=severity,
|
|
323
|
+
ts_hlc=ts_hlc,
|
|
324
|
+
**fields,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
def incr(self, metric: str, *, by: float = 1.0, **labels: Any) -> None:
|
|
328
|
+
self._inner.incr(metric, by=by, **labels)
|
|
329
|
+
|
|
330
|
+
def trace_id(self) -> str:
|
|
331
|
+
return self._inner.trace_id()
|
|
332
|
+
|
|
333
|
+
def filter(self, *, event_type: str | None = None) -> list[LogRecord]:
|
|
334
|
+
return self._inner.filter(event_type=event_type)
|
|
335
|
+
|
|
336
|
+
def get_metrics(self) -> dict[str, Any]:
|
|
337
|
+
return self._inner.get_metrics()
|
|
338
|
+
|
|
339
|
+
def reset(self) -> None:
|
|
340
|
+
self._inner.reset()
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def get_recorder() -> Recorder:
|
|
344
|
+
return _GLOBAL
|