trodo-python 2.23.0__tar.gz → 2.23.2__tar.gz
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.
- {trodo_python-2.23.0 → trodo_python-2.23.2}/PKG-INFO +1 -1
- {trodo_python-2.23.0 → trodo_python-2.23.2}/pyproject.toml +1 -1
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_instrumentor_resolution.py +79 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_prompt_trace.py +77 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/auto_instrument.py +49 -1
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/prompt_trace.py +25 -3
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/wrap_agent.py +4 -2
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo_python.egg-info/PKG-INFO +1 -1
- {trodo_python-2.23.0 → trodo_python-2.23.2}/README.md +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/setup.cfg +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_anon_distinct_id.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_auto_instrument_fixes.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_cross_process_session.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_datasets.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_end_run.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_error_enrichment.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_experiments.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_get_prompt_version_types.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_llm_usage_cost.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_multi_agent_shape.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_processor_methods.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_prompts.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_register_otel.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_start_run.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_user_traits.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/tests/test_wrap_agent_unchanged.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/api/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/api/async_client.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/api/endpoints.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/api/http_client.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/auto/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/auto/auto_event_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/client.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/dataset_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/experiment_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/group_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/people_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/prompt_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/managers/user_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/context.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/helpers.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/processor.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/register.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/otel/transport.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/prompts/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/prompts/compile.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/prompts/template.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/prompts/types.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/queue/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/queue/batch_flusher.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/queue/event_queue.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/session/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/session/server_session.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/session/session_manager.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/types.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/user_context.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/util/__init__.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo/util/lru.py +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo_python.egg-info/SOURCES.txt +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo_python.egg-info/dependency_links.txt +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo_python.egg-info/requires.txt +0 -0
- {trodo_python-2.23.0 → trodo_python-2.23.2}/trodo_python.egg-info/top_level.txt +0 -0
|
@@ -107,3 +107,82 @@ def test_a_missing_module_still_raises_importerror(_clean):
|
|
|
107
107
|
"""The caller relies on ImportError to mean "skip this framework"."""
|
|
108
108
|
with pytest.raises(ImportError):
|
|
109
109
|
_instrument('module_that_does_not_exist_xyz', 'AnyInstrumentor')
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# ── Version conflicts must not be reported as active ────────────────────────
|
|
113
|
+
#
|
|
114
|
+
# An instrumentor whose target library is the wrong VERSION does not raise:
|
|
115
|
+
# OpenTelemetry logs a DependencyConflict and returns without patching. We then
|
|
116
|
+
# appended it to `active` and reported auto-capture that was not happening.
|
|
117
|
+
# Found live: cohere 7.0.9 against the instrumentor's ">=4.2.7, <6" was listed
|
|
118
|
+
# as active while producing no spans — the same lie as Node listing `openai`
|
|
119
|
+
# for a version its instrumentation cannot patch.
|
|
120
|
+
|
|
121
|
+
@pytest.fixture
|
|
122
|
+
def fake_conflict_checker():
|
|
123
|
+
"""Stand in for opentelemetry.instrumentation.dependencies.
|
|
124
|
+
|
|
125
|
+
OpenTelemetry is an OPTIONAL dependency of this SDK, so the suite must not
|
|
126
|
+
require it to be installed — injecting the module is how these tests stay
|
|
127
|
+
runnable in a bare environment.
|
|
128
|
+
"""
|
|
129
|
+
made = []
|
|
130
|
+
|
|
131
|
+
def install(result):
|
|
132
|
+
for mod in ('opentelemetry', 'opentelemetry.instrumentation',
|
|
133
|
+
'opentelemetry.instrumentation.dependencies'):
|
|
134
|
+
if mod not in sys.modules:
|
|
135
|
+
sys.modules[mod] = types.ModuleType(mod)
|
|
136
|
+
made.append(mod)
|
|
137
|
+
sys.modules['opentelemetry.instrumentation.dependencies'].get_dependency_conflicts = (
|
|
138
|
+
lambda deps: result
|
|
139
|
+
)
|
|
140
|
+
yield install
|
|
141
|
+
for m in made:
|
|
142
|
+
sys.modules.pop(m, None)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_a_version_conflict_is_raised_not_swallowed(_clean, fake_conflict_checker):
|
|
146
|
+
name = 'fake_instr_conflict'
|
|
147
|
+
_clean.append(name)
|
|
148
|
+
|
|
149
|
+
class Conflicted(_Recorder):
|
|
150
|
+
instrumented = False
|
|
151
|
+
|
|
152
|
+
def instrumentation_dependencies(self):
|
|
153
|
+
return ('somelib >=1, <2',)
|
|
154
|
+
|
|
155
|
+
_fake_module(name, ConflictedInstrumentor=Conflicted)
|
|
156
|
+
fake_conflict_checker('DependencyConflict: requested "somelib >=1, <2" but found "somelib 3.0"')
|
|
157
|
+
from trodo.otel.auto_instrument import _IncompatibleInstrumentation
|
|
158
|
+
|
|
159
|
+
with pytest.raises(_IncompatibleInstrumentation, match='somelib 3.0'):
|
|
160
|
+
_instrument(name, 'ConflictedInstrumentor')
|
|
161
|
+
assert Conflicted.instrumented is False # and it never patched
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_no_conflict_instruments_normally(_clean, fake_conflict_checker):
|
|
165
|
+
name = 'fake_instr_ok'
|
|
166
|
+
_clean.append(name)
|
|
167
|
+
|
|
168
|
+
class Fine(_Recorder):
|
|
169
|
+
instrumented = False
|
|
170
|
+
|
|
171
|
+
def instrumentation_dependencies(self):
|
|
172
|
+
return ('somelib >=1',)
|
|
173
|
+
|
|
174
|
+
_fake_module(name, FineInstrumentor=Fine)
|
|
175
|
+
fake_conflict_checker(None)
|
|
176
|
+
_instrument(name, 'FineInstrumentor')
|
|
177
|
+
assert Fine.instrumented is True
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_unknowable_conflict_state_fails_open(_clean):
|
|
181
|
+
"""No dependency helper, or an instrumentor that declares nothing, must not
|
|
182
|
+
be condemned — falsely reporting a working setup as broken is worse."""
|
|
183
|
+
name = 'fake_instr_nodeps'
|
|
184
|
+
_clean.append(name)
|
|
185
|
+
cls = type('NoDepsInstrumentor', (_Recorder,), {'instrumented': False})
|
|
186
|
+
_fake_module(name, NoDepsInstrumentor=cls)
|
|
187
|
+
_instrument(name, 'NoDepsInstrumentor')
|
|
188
|
+
assert cls.instrumented is True
|
|
@@ -259,3 +259,80 @@ def test_run_set_input_with_ordinary_input_records_nothing(processor, http):
|
|
|
259
259
|
|
|
260
260
|
attrs = http.run_ingest[0]["run"].get("attributes") or {}
|
|
261
261
|
assert "trodo.prompts" not in attrs
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# ── Prompts are SPAN-level, not run-level ───────────────────────────────────
|
|
265
|
+
#
|
|
266
|
+
# One run's spans routinely use different prompts, different versions, or none.
|
|
267
|
+
# The run's "most recently compiled" prompt is a fallback, and applying it to
|
|
268
|
+
# every span meant compiling anywhere in a run attributed that prompt to every
|
|
269
|
+
# LATER span. Caught in production: a span named 'no-prompt' was labelled with
|
|
270
|
+
# whichever prompt had been compiled last.
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def test_does_not_leak_last_prompt_onto_a_later_unrelated_span(processor, http):
|
|
274
|
+
mgr = PromptManager(PromptHttp(prompt=PROMPT_WIRE))
|
|
275
|
+
with wrap_agent(processor=processor, team_site_id="site-x", agent_name="chat"):
|
|
276
|
+
p = mgr.get("refund-agent", cache_ttl_seconds=0)
|
|
277
|
+
with span("used-it", kind="llm"):
|
|
278
|
+
p.compile(q="x")
|
|
279
|
+
with span("unrelated"):
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
spans = http.run_ingest[0]["spans"]
|
|
283
|
+
attrs = next(s for s in spans if s["name"] == "unrelated").get("attributes") or {}
|
|
284
|
+
assert "trodo.prompt.name" not in attrs
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def test_still_labels_a_model_span_following_a_compile(processor, http):
|
|
288
|
+
mgr = PromptManager(PromptHttp(prompt=PROMPT_WIRE))
|
|
289
|
+
with wrap_agent(processor=processor, team_site_id="site-x", agent_name="chat"):
|
|
290
|
+
p = mgr.get("refund-agent", cache_ttl_seconds=0)
|
|
291
|
+
p.compile(q="x")
|
|
292
|
+
with span("model-call", kind="llm"):
|
|
293
|
+
pass
|
|
294
|
+
|
|
295
|
+
spans = http.run_ingest[0]["spans"]
|
|
296
|
+
attrs = next(s for s in spans if s["name"] == "model-call")["attributes"]
|
|
297
|
+
assert attrs["trodo.prompt.name"] == "refund-agent"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def test_labels_the_span_the_prompt_was_compiled_inside(processor, http):
|
|
301
|
+
"""A plain span wrapping a hand-rolled model call plainly used the prompt
|
|
302
|
+
it compiled; gating purely on kind would have lost it."""
|
|
303
|
+
mgr = PromptManager(PromptHttp(prompt=PROMPT_WIRE))
|
|
304
|
+
with wrap_agent(processor=processor, team_site_id="site-x", agent_name="chat"):
|
|
305
|
+
p = mgr.get("refund-agent", cache_ttl_seconds=0)
|
|
306
|
+
with span("hand-rolled"):
|
|
307
|
+
p.compile(q="x")
|
|
308
|
+
|
|
309
|
+
spans = http.run_ingest[0]["spans"]
|
|
310
|
+
attrs = next(s for s in spans if s["name"] == "hand-rolled")["attributes"]
|
|
311
|
+
assert attrs["trodo.prompt.name"] == "refund-agent"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def test_each_span_gets_its_own_prompt_and_the_run_rolls_up_both(processor, http):
|
|
315
|
+
other = dict(PROMPT_WIRE, name="other-agent", version_hash="bbbb2222")
|
|
316
|
+
|
|
317
|
+
class Two:
|
|
318
|
+
def get_prompt(self, name, label=None, version=None):
|
|
319
|
+
return {"prompt": dict(other if name == "other-agent" else PROMPT_WIRE)}
|
|
320
|
+
|
|
321
|
+
mgr = PromptManager(Two())
|
|
322
|
+
with wrap_agent(processor=processor, team_site_id="site-x", agent_name="chat"):
|
|
323
|
+
a = mgr.get("refund-agent", cache_ttl_seconds=0)
|
|
324
|
+
b = mgr.get("other-agent", cache_ttl_seconds=0)
|
|
325
|
+
with span("span-a", kind="llm"):
|
|
326
|
+
a.compile(q="x")
|
|
327
|
+
with span("span-b", kind="llm"):
|
|
328
|
+
b.compile(q="y")
|
|
329
|
+
with span("span-c"):
|
|
330
|
+
pass
|
|
331
|
+
|
|
332
|
+
spans = http.run_ingest[0]["spans"]
|
|
333
|
+
at = lambda n: (next(s for s in spans if s["name"] == n).get("attributes") or {})
|
|
334
|
+
assert at("span-a")["trodo.prompt.name"] == "refund-agent"
|
|
335
|
+
assert at("span-b")["trodo.prompt.name"] == "other-agent"
|
|
336
|
+
assert "trodo.prompt.name" not in at("span-c")
|
|
337
|
+
used = http.run_ingest[0]["run"]["attributes"]["trodo.prompts"]
|
|
338
|
+
assert sorted(r["name"] for r in used) == ["other-agent", "refund-agent"]
|
|
@@ -438,7 +438,44 @@ def _instrument(module_name: str, *preferred: str) -> None:
|
|
|
438
438
|
)
|
|
439
439
|
if cls is None:
|
|
440
440
|
raise ImportError(f"no Instrumentor class exported by {module_name}")
|
|
441
|
-
|
|
441
|
+
|
|
442
|
+
instr = cls()
|
|
443
|
+
|
|
444
|
+
# An instrumentor whose target library is the wrong VERSION does not raise:
|
|
445
|
+
# OpenTelemetry logs a DependencyConflict and returns without patching
|
|
446
|
+
# anything. We would then append it to `active` and report auto-capture that
|
|
447
|
+
# is not happening -- the same lie as listing a framework whose
|
|
448
|
+
# instrumentation cannot patch the installed SDK. Ask first, and let the
|
|
449
|
+
# caller report it honestly.
|
|
450
|
+
conflict = _dependency_conflict(instr)
|
|
451
|
+
if conflict is not None:
|
|
452
|
+
raise _IncompatibleInstrumentation(str(conflict))
|
|
453
|
+
|
|
454
|
+
instr.instrument()
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class _IncompatibleInstrumentation(ImportError):
|
|
458
|
+
"""The instrumentor loaded, but its target library is an unsupported version."""
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _dependency_conflict(instr: Any) -> Any:
|
|
462
|
+
"""The version conflict OpenTelemetry would hit, or None.
|
|
463
|
+
|
|
464
|
+
Returns None when we cannot tell -- an older OTel without the helper, or an
|
|
465
|
+
instrumentor that declares nothing. Falsely reporting a working setup as
|
|
466
|
+
broken is worse than the silence this replaces.
|
|
467
|
+
"""
|
|
468
|
+
try:
|
|
469
|
+
from opentelemetry.instrumentation.dependencies import ( # type: ignore
|
|
470
|
+
get_dependency_conflicts,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
deps = instr.instrumentation_dependencies()
|
|
474
|
+
if not deps:
|
|
475
|
+
return None
|
|
476
|
+
return get_dependency_conflicts(deps)
|
|
477
|
+
except Exception: # noqa: BLE001
|
|
478
|
+
return None
|
|
442
479
|
|
|
443
480
|
|
|
444
481
|
_INSTRUMENTORS: List[tuple[str, Callable[[], Any]]] = []
|
|
@@ -556,6 +593,17 @@ def enable_auto_instrument(
|
|
|
556
593
|
try:
|
|
557
594
|
register()
|
|
558
595
|
active.append(name)
|
|
596
|
+
except _IncompatibleInstrumentation as e:
|
|
597
|
+
# Loud, because this is the case where everything LOOKS installed:
|
|
598
|
+
# the package is present, the import worked, and no spans will ever
|
|
599
|
+
# appear. Silence here is what costs people an afternoon.
|
|
600
|
+
_warn_once(
|
|
601
|
+
f"version-{name}",
|
|
602
|
+
f"auto-instrument: {name} will NOT be auto-captured and is not "
|
|
603
|
+
f"reported as active -- {e}. Wrap the call with trodo.llm(...) "
|
|
604
|
+
f"to capture it, or pin the library to a supported version.",
|
|
605
|
+
)
|
|
606
|
+
continue
|
|
559
607
|
except Exception:
|
|
560
608
|
continue
|
|
561
609
|
return active
|
|
@@ -25,7 +25,7 @@ PromptRef = Dict[str, Any]
|
|
|
25
25
|
|
|
26
26
|
def new_prompt_state() -> Dict[str, Any]:
|
|
27
27
|
"""Per-run accumulator, shared by reference across the run's span tree."""
|
|
28
|
-
return {"current": None, "all": []}
|
|
28
|
+
return {"current": None, "current_span_id": None, "all": []}
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
# Compiled prompt (or its messages list) -> the version it came from.
|
|
@@ -93,6 +93,7 @@ def record_compiled_prompt(ref: PromptRef) -> None:
|
|
|
93
93
|
state = getattr(active, "prompt_state", None) if active is not None else None
|
|
94
94
|
if isinstance(state, dict):
|
|
95
95
|
state["current"] = ref
|
|
96
|
+
state["current_span_id"] = getattr(active, "span_id", None)
|
|
96
97
|
key = _ref_key(ref)
|
|
97
98
|
used: List[PromptRef] = state["all"]
|
|
98
99
|
if not any(_ref_key(r) == key for r in used):
|
|
@@ -116,7 +117,11 @@ def prompt_attributes(ref: Optional[PromptRef]) -> Dict[str, str]:
|
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
def merge_prompt_attrs(
|
|
119
|
-
active: Any,
|
|
120
|
+
active: Any,
|
|
121
|
+
attrs: Optional[Dict[str, Any]],
|
|
122
|
+
from_input: Optional[PromptRef] = None,
|
|
123
|
+
kind: Optional[str] = None,
|
|
124
|
+
span_id: Optional[str] = None,
|
|
120
125
|
) -> Optional[Dict[str, Any]]:
|
|
121
126
|
"""Merge the prompt this span used into its attributes.
|
|
122
127
|
|
|
@@ -134,7 +139,24 @@ def merge_prompt_attrs(
|
|
|
134
139
|
remember_prompt(state, from_input)
|
|
135
140
|
merged.update(prompt_attributes(from_input))
|
|
136
141
|
elif isinstance(state, dict):
|
|
137
|
-
|
|
142
|
+
# The run's "most recently compiled" prompt is a FALLBACK, used only
|
|
143
|
+
# where it is defensible. Applying it to every span meant compiling a
|
|
144
|
+
# prompt anywhere in a run attributed it to every LATER span -- a tool,
|
|
145
|
+
# a retrieval, a bit of plain work all claiming a prompt they never ran.
|
|
146
|
+
# Prompts belong to SPANS: one run's spans routinely use different
|
|
147
|
+
# prompts, different versions, or none at all.
|
|
148
|
+
#
|
|
149
|
+
# Two cases survive: a MODEL call (kind 'llm'), the only thing that runs
|
|
150
|
+
# a prompt and the one shape whose input we cannot read when it comes
|
|
151
|
+
# from a provider instrumentation; and the very span the prompt was
|
|
152
|
+
# compiled INSIDE, which plainly used it whatever its kind.
|
|
153
|
+
compiled_here = (
|
|
154
|
+
state.get("current") is not None
|
|
155
|
+
and span_id is not None
|
|
156
|
+
and state.get("current_span_id") == span_id
|
|
157
|
+
)
|
|
158
|
+
if kind == "llm" or compiled_here:
|
|
159
|
+
merged.update(prompt_attributes(state.get("current")))
|
|
138
160
|
return merged or None
|
|
139
161
|
|
|
140
162
|
|
|
@@ -876,7 +876,8 @@ class join_run:
|
|
|
876
876
|
temperature=self.handle.temperature,
|
|
877
877
|
tool_name=self.handle.tool_name,
|
|
878
878
|
attributes=merge_prompt_attrs(
|
|
879
|
-
self._ctx, self.handle.attributes, self.handle.prompt_ref
|
|
879
|
+
self._ctx, self.handle.attributes, self.handle.prompt_ref,
|
|
880
|
+
self._kind, self._span_id,
|
|
880
881
|
),
|
|
881
882
|
)
|
|
882
883
|
try:
|
|
@@ -988,7 +989,8 @@ class span:
|
|
|
988
989
|
temperature=self.handle.temperature,
|
|
989
990
|
tool_name=self.handle.tool_name,
|
|
990
991
|
attributes=merge_prompt_attrs(
|
|
991
|
-
self._active, self.handle.attributes, self.handle.prompt_ref
|
|
992
|
+
self._active, self.handle.attributes, self.handle.prompt_ref,
|
|
993
|
+
self._kind, self._span_id,
|
|
992
994
|
),
|
|
993
995
|
)
|
|
994
996
|
processor: TrodoSpanProcessor = self._active.processor # type: ignore[assignment]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|