Repository navigation
feat(python): hide error details with the content hide flags - #272
Merged
Merged
Conversation
Error text is content. Provider error bodies quote the prompt back and carry
request/session ids; Python tracebacks carry local file paths. With content
hidden, traceAI still exported them: LangChain put repr + full traceback in
the status description, and every exception event kept exception.message and
exception.stacktrace.
Core (fi-instrumentation-otel 1.2.0):
- TraceConfig.hide_error_details / FI_HIDE_ERROR_DETAILS. Unset, it is on
when any of hide_inputs, hide_outputs, hide_input_messages,
hide_output_messages, hide_input_text, hide_output_text is on; an explicit
true/false wins.
- Enforced once, in FiSpan: record_exception, add_event("exception"),
set_status and set_attribute(s). This also covers the OTel API's own
use_span / start_as_current_span exception handling. When on, ERROR has no
description, exception events keep only exception.type/escaped, and
error.message / exception.* / *.error.message keys are dropped.
- Always: error.type (provider code or fully qualified class), and an ERROR
description that is the exception message only, never a traceback.
- `with tracer.start_span(...) as span` now yields the FiSpan, not the raw
SDK span.
LangChain (traceAI-langchain 0.2.1): the status description comes from the
error passed to on_*_error, not run.error; the stacktrace stays only on the
exception event.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
…rough FITracer LangChain (traceAI-langchain 0.2.1): langchain-core fills a failed chat-model run's outputs with the provider's error response (error body, response headers, request ids, AI-gateway metadata). With error details hidden, a failed run now records no output attributes. Found in the local end-to-end run: with FI_HIDE_INPUTS=true the ChatOpenAI span still stored the CLIProxy error body and response headers in output.value. AutoGen (traceAI-autogen 0.2.1): agent, team and tool spans were created with a raw OpenTelemetry tracer, so TraceConfig (and the FiSpan error handling) never applied. They now use the instrumentor's FITracer. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…m provider SDKs Review follow-ups for the hide-error-details change: - error.type is set when the span ends with status ERROR (from the exception handled when the status was set, else the last recorded one). An exception recorded on a span that still ends OK, such as a recovered retry, no longer sets it. use_span / start_as_current_span auto-recording is unchanged. - Provider error codes are read only from exceptions of known provider SDKs (or their subclasses): openai, anthropic, groq, litellm, botocore/boto3, google-genai, google-api-core, mistralai, and the HTTP status for httpx HTTPStatusError. Everything else gets the fully qualified class name, so SQLAlchemy's "e3q8" or Django's "invalid" are no longer used as error.type. - TraceConfig keeps the raw hide_error_details setting in a private field and resolves it in a property, so dataclasses.replace(TraceConfig(), hide_inputs=True).hide_error_details is True. The constructor argument, attribute and env var are unchanged. - FiSpan keeps only summaries (class names, message) of recorded exceptions, cleared at end(), never the exception, so traceback frames and locals are not held. - An ERROR description that joins one "Type: msg" line per exception (llama-index) is reduced to the messages in default mode. - instrumentation/version.py now says 1.2.0, like pyproject. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…w.output, error.type fallback - clean_error_description no longer builds a regex from exception messages. It compiled and ran one on every ERROR set_status in default mode (100 KB message: 0.83 s, 1 MB: 6.4 s) and left each message in the global re cache. It now strips the known "<Type>: " line prefixes with str.find/startswith (1 MB: ~1 ms). - Content-hiding fix: hide_inputs also redacts raw.input and the prompt template variables; hide_outputs also redacts raw.output (same keys as @traceai/fi-core). - error.type: ERROR with no exception to name gets "_OTHER"; a recovered exception the status does not mention is no longer used; the in-flight exception, an exception recorded as escaped, or a recorded one the status description mentions still are. - Correct the litellm comment: its exceptions carry no code/type. Co-Authored-By: Claude Opus 5.5 <[email protected]>
9 of 10 tasks
11 of 12 tasks
nik13
added a commit
that referenced
this pull request
Oct 21, 2026
… on a provider that keeps its exporter (TH-8727) 43e25de skipped Strands' OTLP exporter whenever a processor on the provider exported to the same host and port. Review found two ways that loses spans: - On fi-instrumentation-otel 1.1.0, register() still marks its exporter as a default the next add_span_processor() call replaces. With OTEL_EXPORTER_OTLP_* at Future AGI, the skip left that marked exporter as the only one, and the next processor (enable_console_exporter=True, or one the application adds) replaced it: Future AGI got nothing. traceai-strands 0.1.0 never hit this, because Strands' own exporter consumed the mark. - When register() ran without FI keys and the keys reached Strands' exporter through otlp_headers or OTEL_EXPORTER_OTLP_HEADERS, the skip removed the only exporter Future AGI would accept. The exporter is now skipped only when all of these hold: - the provider would keep its exporter on the next add_span_processor() call: no `_default_processor` mark on that provider. This is the flag the core's add_span_processor() override reads, checked on the provider being configured rather than through a version number. On 1.1.0 Strands' exporter is then added exactly as in 0.1.0. A bare fi_instrumentation TracerProvider() whose construction default is still pending replacement is covered by the same check. - a processor on the provider exports to the same traces URL: scheme, userinfo, host, port (default filled in), path (repeated and trailing slashes dropped) and query, instead of host and port only; - that exporter already sends every header Strands' exporter would send, with the same value, and no client certificate or credential provider is set for Strands' exporter. Strands' endpoint and headers come from an upstream OTLPSpanExporter built with no arguments, as Strands builds it, read back and shut down. That follows the installed exporter release: 1.45 merges environment headers into passed ones and moved them to `_client`, and treats an empty OTEL_EXPORTER_OTLP_TRACES_ENDPOINT differently from 1.29-1.39. A floor of fi-instrumentation-otel>=1.1.1 was not added: it would make traceai-strands 0.1.1 uninstallable until the core is published (and fail this repo's CI install from PyPI), tie it to a version number that changes if #272 ships first, and still not protect an environment resolved without it (--no-deps, a lock pinned to 1.1.0). Tests: unit tests for each rule (URL parts and spellings, keys only on one side, other keys, x-project-name, unreadable headers, mTLS and credential-provider variables, both header layouts, the marked provider). README Option 1 run for real, now also with the console exporter, a processor added afterwards, keys only on Strands' exporter and a base endpoint, on the repo core and on 1.1.0. README Option 1 and the CHANGELOG say exactly when the exporter is added. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
nik13
marked this pull request as ready for review
October 21, 2026 23:43
nik13
added a commit
that referenced
this pull request
Oct 22, 2026
The repo now releases dev -> main (#283), and #271/#272 target dev, so this PR moves to dev too. Changing the base does not start the pull_request workflows; this empty commit does. Co-Authored-By: Claude Opus 5.5 <[email protected]>
nik13
added a commit
that referenced
this pull request
Oct 26, 2026
Brings in #272 (fi-instrumentation-otel 1.2.0, error-detail hiding) and #203. Conflicts were only the version lines: this fix becomes 1.2.1, as planned in the PR notes for the case where #272 merges first. pyproject.toml, CHANGELOG.md and fi_instrumentation/instrumentation/version.py all read 1.2.1; the 1.2.1 entry sits above 1.2.0. 1.2.0 was never published (PyPI latest is 1.1.0), so the READMEs and the livekit test keep naming 1.1.0 as the last release with the mark. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Treats error text as content on the Python side. When content is hidden, failed spans keep status
ERROR,error.typeandexception.type, and drop the status description,exception.message,exception.stacktrace,error.messageand the provider error response. When content is shown, theERRORdescription is the exception message only, never a traceback.Behaviour change for users of the hide flags: setting any of
hide_inputs,hide_outputs,hide_input_messages,hide_output_messages,hide_input_textorhide_output_text(or theirFI_HIDE_*env vars) now also hides error details. Sethide_error_details=False/FI_HIDE_ERROR_DETAILS=falseto keep the old behaviour.Why?
Decision (2026-10-18): do what the other tracing SDKs do. OpenInference, OpenLLMetry, OpenLIT, OTel util-genai, Langfuse, LangSmith, Braintrust and Datadog all keep error text when content capture is off. Pydantic AI was the exception and got GHSA-4x9p-g9wm-8q7f (CVE-2026-107291) for it. Its fix keeps only
exception.typeon the exception event and sets ERROR with no description wheninclude_content=False. The OTel spec also says the status description SHOULD NOT carry sensitive details, and thatexception.messagemay contain sensitive information.Leaks we hit with content hidden:
repr(error)plus the full Python traceback (including a local/private/tmppath) instatus_message(TH-8226 AgentCore recipe). traceAI got this from OpenInference:status.description = run.error.How
Core,
fi-instrumentation-otel1.1.0 → 1.2.0TraceConfig.hide_error_details/FI_HIDE_ERROR_DETAILShas three states. If neither the argument nor the env var is set, it is derived: on when any of the six content hide flags above is on. An explicittrue/false, from the constructor or the env var, wins. The raw setting lives in a private field (_hide_error_details) andhide_error_detailsis a property that resolves it, sodataclasses.replace(TraceConfig(), hide_inputs=True).hide_error_detailsisTrue, while an explicit value survivesreplace(). The constructor argument, the attribute and the env var are unchanged.FiSpan(_spans.py), throughrecord_exception,add_event("exception"),set_status,set_attribute(s)/TraceConfig.mask, and__enter__/__exit__. That also covers OpenTelemetry's ownuse_span/start_as_current_spanexception handling (which builds"Type: msg"and callsrecord_exception) andwith tracer.start_span(...) as span:. That block used to yield the raw SDK span; it now yields theFiSpan.ERRORhas no description. Exception events keep onlyexception.typeandexception.escaped.error.message,exception.message,exception.stacktraceand any key ending in.exception.message,.exception.stacktrace,.error.messageor.error_messageare dropped (for exampleautogen.error.messageandautogen.tool.error_message).error.typeis set only on a span that ends with statusERROR(checked inend()), from the exception being handled when the status was set, or else the last recorded one. An exception recorded on a span that still ends OK, such as a recovered retry, does not set it (OTel semconv:error.typemarks a failed operation).The provider error code is read only from exceptions of known provider SDKs, or subclasses of them (the class MRO is checked, so langchain-openai's
OpenAIInvalidRequestError, a subclass ofopenai.BadRequestError, still maps):code,body["error"]["code"/"type"],typemodel_not_found,invalid_request_error,not_found_errorresponse["Error"]["Code"]ValidationExceptionstatusNOT_FOUNDgrpc_status_code.nameNOT_FOUNDbodytype/codeinvalid_modelHTTPStatusErrorresponse.status_code"404"Everything else gets the fully qualified exception class. A generic
.code/.status/.typelookup is not used, because other libraries put short codes there too (SQLAlchemye3q8, DjangoValidationErrorinvalid). cohere errors carry only a status code and a free-text body, so they get the class name. Free text is never used as a code. An instrumentor's ownerror.typeis not overwritten.The
ERRORdescription is reduced tostr(exc):"Type: msg"becomesmsg, also when one such line is joined per exception (llama-index_callback.py), and anything fromTraceback (most recent call last)onwards is cut.FiSpankeeps only a summary (class names and message) of each recorded exception, and clears it inend(). It never holds the exception, so traceback frames and their locals are not kept alive.fi_instrumentation/instrumentation/version.pynow says 1.2.0, likepyproject.toml(it still said 0.1.19)._errors.pyholds the helpers. Docs updated:docs/configuration/trace-config.md,environment-variables.mdandpython/README.md.LangChain,
traceAI-langchain0.2.0 → 0.2.1on_*_error, not fromrun.error(reprplus the traceback). The stacktrace stays only inexception.stacktraceon the exception event. Non-Exceptionerrors record their own traceback, nottraceback.format_exc().FI_HIDE_INPUTS=true, theChatOpenAIspan still stored that response inoutput.value.AutoGen,
traceAI-autogen0.2.0 → 0.2.1FITracerbut then created every agent, team and tool span with a separate raw tracer, soTraceConfignever applied to them. These spans now use theFITracer.Instrumentor audit
Every instrumentor that builds its spans through
FITraceris covered by theFiSpanenforcement, with no per-instrumentor change: anthropic, bedrock, cerebras, cohere, crewai, deepseek, dspy, fireworks, google-adk, google-genai, groq, guardrails, haystack, huggingface, instructor, langchain, litellm, llama_index, mistralai, ollama, openai, openai-agents, portkey, smolagents, together, vertexai, vllm and xai. I checked the named ones by reading their code:_WithSpan/_stream.py._wrappers.pysetsstr(exception)from inside theexcept.start_as_current_spanplusrecord_exception._wrappers.py,_response_accumulator.py,utils._finish, and theinvoke_modelpath that ends the span before re-raising.error.typestill lands:set_statusruns inside theexcept, and the span ends throughFiSpan.end()with statusERROR._wrappers.py/_stream.py.None of these hold raw spans or format tracebacks themselves. The only
traceback.format_*call left inpython/frameworksis LangChain's exception event.Fixed here: autogen (raw tracer, above) and langchain (
run.errorand failed-run outputs).Follow-ups (not in this PR):
Instrumentors that don't use
FITracer. They take noTraceConfig, so neither the content hide flags norhide_error_detailsapply to them. They setstr(e)/f"{type(e).__name__}: {e}"status descriptions and callrecord_exceptionon raw spans, which keeps the message and the stacktrace:a2a/traceai_a2a/_a2a_client.py,a2a/traceai_a2a/_a2a_server.pybeeai/traceai_beeai/_middleware.pystrands/traceai_strands/_callback.pyclaude-agent-sdk/traceai_claude_agent_sdk/{_hooks,_client_wrapper,_subagent_tracker}.py, which also setclaude_agent.error.messageandclaude_agent.tool.error_messagepydantic-ai/traceai_pydantic_ai/{_instrumentor,_agent_wrapper}.py, which also setpydantic_ai.error.messageandpydantic_ai.tool.error_messagechromadb,lancedb,milvus,mongodb-vector,pgvector,pinecone,qdrant,redis-vectorandweaviate(_wrappers.pyin each)agnoandpipecatexport the framework's own OTel spans as they are;mcponly propagates context.livekit/traceai_livekitrewrites livekit-agents' own OTel spans at the exporter and takes noTraceConfig, so error text and content on those spans pass through untouched.Fix: build these spans through
FITracer, or scrub at export time inregister().autogen content keys.
autogen.input.last_message,autogen.output.content,autogen.task.contentandautogen.tool.argsare custom keys, sohide_inputs/hide_outputsdon't mask them.openai-agents. A failed Agents-SDK span gets the description
"{message}: {data}"from the SDK'sSpanError. There is no Python exception, so it gets noerror.type. Hidden mode drops the description; default mode keepsdata.LiteLLM streaming, pre-existing and unrelated to hiding. On the sync path, an error before the first chunk records the exception but never sets ERROR or ends the span. The async path calls
span_cm.__exit__(e, type(e), tb)with the arguments swapped.How was it tested?
Unit tests:
python/tests/test_error_details.py(116 tests):hide_error_details; non-content flags don't; an explicit or envfalseoverrides; the constructor beats the env; an invalid env value falls back to the derived valuedataclasses.replace(): derives it again for each flag, keeps an explicit or env value, takes an explicithide_error_details; positional arguments still workmaskerror.typeextraction: each provider SDK above (including subclasses and the class-name fallbacks), and SQLAlchemy / Django / other libraries with short.code/.statusvalues getting the class nameerror.typeonly on failed spans: recovered retry ending OK, no status, exception event without ERROR, ERROR then OK, retry then failure (the failing exception wins), status set outsideexcept(LangChain), status beforerecord_exception, hidden modeend())"Type: msg"line per exceptionrecord_exception,set_status(in both forms),add_event("exception")andset_attributeuse_span/start_as_current_spanauto-recording, the span used as a context manager, the decorator path, and suppressed spanspython/frameworks/langchain/tests/test_error_status.py(11 tests): message-only description on chain and LLM runs, hidden mode (derived and explicit), explicitfalse, therun.errorfallback, the bare-span check on_update_span, and failed-run outputs (kept by default, dropped when hidden). I checked that the new output tests fail without the fix. Its fake provider error now claims theopenaimodule, since codes are read only from provider SDKs.3f43aa2), as expected: thereplace(), provider-only, failed-span-only, frames-held and multi-line cases.Suites:
pytest tests --ignore-glob='tests/test_framework_*' --ignore=tests/test_otel.pygives 256 passed, 1 skipped and 12 failed. The same 12 fail onorigin/dev(test_batch_span_processor_tuning×3,test_context_attributes×8,test_settings×1), andtests/test_otel.pyfails to import onorigin/devtoo.test_framework_{openai,langchain}.py,test_tracers.py,test_config.py,test_error_details.py: 206 passed, 4 failed; the same 4 fail on3f43aa2.test_error_details.py,test_config.pyandtest_tracers.pyalso pass on the minimum OpenTelemetry 1.29.ruff checkreports no new rule categories on the changed files, only more of theOptional[...]style hints (UP045) that the Python 3.9 floor requires.mypypasses on_errors.py,_spans.pyandconfig.py.Real SDK exceptions →
error.type: OpenAI through CLIProxy (model_not_found), Anthropic through CLIProxy (invalid_request_error, which is what CLIProxy returns for an unknown Claude model) and against an Anthropic-shaped 404 (not_found_error), the real Gemini API with an unknown model (NOT_FOUND), groq / mistralai / cohere against a local server returning their documented error bodies (model_not_found/invalid_model/ class name), botocorebedrock-runtimeviaStubber(ValidationException),google.api_core.exceptions.NotFound(NOT_FOUND), httpxraise_for_status()("503"), and realsqlalchemy.exc.OperationalError(.code == "e3q8") and DjangoValidationError(code="invalid"), which both get the class name.End-to-end against the local Future AGI (project
th8103-hideerr-python). Each run has one root span with three real failures:model_not_foundChatOpenAIchain calling the same bad modelFITracer.start_as_current_spanblock that raises with a local/private/tmppath in the message, recorded byuse_spanStored ClickHouse rows:
status_messageuse_spanstatus_messageerror.type/private/tmpin roworigin/dev,FI_HIDE_INPUTS=trueOpenAIInvalidRequestError("Error code: 400 ...")Traceback (most recent call last): ...(5,516 chars)FileNotFoundError: [Errno 2] ... '/private/tmp/...' (prompt)output.valuehad the body and the response headers)Error code: 400 - {'error': {... 'code': 'model_not_found' ...}}(message only)[Errno 2] No such file or directory: '/private/tmp/...'(message only)model_not_found/FileNotFoundErrorFI_HIDE_INPUTS=truemodel_not_found/FileNotFoundErrorAll 10 failed spans were stored with status
ERRORin both runs. The local backend keeps only event names and timestamps inspan_events, so I checked the exception-event attributes on the spans exported in the same runs. Default mode hadexception.type/message/stacktrace/escaped. Hidden mode hadexception.type/escapedonly.End-to-end after the review follow-ups (head
c845102, projectth8103-hideerr-python-r2): the three failures above plus four new cases. Stored ClickHouse rows:status_messagestatus_messageerror.type(both runs)ChatCompletion(×2), LangChain chain,ChatOpenAImodel_not_founduse_spanwith a/private/tmppathFileNotFoundErrorTimeoutErrorrecorded, span ends OKuse_span404 NOT_FOUND. {...}NOT_FOUNDsqlalchemy.exc.OperationalError(.code=e3q8)sqlalchemy.exc.OperationalErrorfirst failure: ...\n'missing_key'(no type prefixes)KeyErrorA scan of every stored column (
status_message,input,output,attrs_string,span_events,attributes_extra,tags) of the hidden run's 10 rows found no prompt text, path, traceback, SQL, provider message orresponse_metadata. The default run has no traceback in any column.Notes for reviewers
traceAI-langchainandtraceAI-autogenkeep theirfi-instrumentation-otelpins. The LangChain change readshide_error_detailswithgetattr, so it also works with core 1.1.x, where hiding just isn't available. Publish core 1.2.0 first, or together with them.FiSpan.set_statustakes the exception fromsys.exc_info()when it is called inside anexceptblock (use_spanand most instrumentors do this), or else from the lastrecord_exception. Order doesn't matter.error.typeitself is written inFiSpan.end(), and only when the span's final status (span.status) isERROR.TraceConfig.__init__is now written by hand: the public argumenthide_error_detailsfills the private field, andreplace()passes the private field by name.dataclasses.fields(TraceConfig)and thereprshow_hide_error_details(the raw value). mypy's dataclass plugin typesdataclasses.replace()by field name, soreplace(config, hide_error_details=...)works at runtime but mypy flags it; the constructor and the attribute type-check as before.feat/hide-error-details-ts).🤖 Generated with Claude Code
Round 3 (2026-10-19)
clean_error_descriptionbuilt a regex containing each exception message and ran it on every ERRORset_statusin default mode (10 KB: 8 ms, 100 KB: 0.83 s, 1 MB: 6.4 s; a LangChain parser error carrying 100 KB went from 9 ms to 0.58 s inchain.invoke), and every distinct message stayed in the globalrecache after the span ended. It now strips the known<Type>:line prefixes withstr.find/startswith; message text never goes into a regex (100 KB: 0.0001 s). Tests: 1 MB message under 0.1 s, many 100 KB messages, and therecache does not grow over 100 distinct messages.hide_inputsnow also redactsraw.inputand the prompt template variables (llm.prompt_template.variables,gen_ai.prompt.template.variables);hide_outputsalso redactsraw.output. Same keys as@traceai/fi-core1.1.0 (traceAI#271). Before, a span carrying these kept the prompt in the stored row with the flag on. Unit tests per key; CHANGELOG entry.code/body. Real litellm 1.106 exceptions havecode=None,body=None,type=None, so a litellm 404 getslitellm.exceptions.NotFoundError(class name). litellm is no longer listed as a provider-code reader in the docs; no special-casing added.error.typefallback. An ERROR status with nothing to name gets_OTHER(OTel semconv). The fallback no longer uses a stale recovered exception: order is the in-flight exception (sys.exc_info()atset_status), then an exception recorded withescaped=Trueon this span, then the newest recorded exception the status description mentions (the LangChain pattern: record in a callback, set the status later), else_OTHER. Recovered retries still leave the span OK withouterror.type;use_spanstill names the exception. Tests added for each case.Stored-row verification (2026-10-19, head 78c56ae)
Ran a real e2e against a local Future AGI stack: a LangChain parser error with a ~230 KB message quoting the prompt, an OpenAI bad-model call through a proxy, a span carrying
raw.input/raw.output/template variables, and ause_spanfailure on a path. I then scanned every stored ClickHousespanscolumn of every row. fi_verify passed in all three modes.error.type=OutputParserException/model_not_found/FileNotFoundErrorFileNotFoundError's own message)FI_HIDE_INPUTS=trueerror.typekeptraw.output, output messages,output.value) and in the fake test model'srequest.parameters(its canned responses)FI_HIDE_INPUTS+FI_HIDE_OUTPUTSerror.typekeptchain.invokeCPU time was 0.05–0.07 s with the 230 KB message. Wall time was dominated by slow exports on a heavily loaded machine.Merged
dev(2026-10-21,99d1a55)The branch was 41 commits behind
devand CI had never run on it (thePython testsworkflow reacheddevafter the last push).devmerged in with no conflicts (merge commit99d1a55). Local checks on the merge, Python 3.11, Poetry 2.1.2 with the locks CI uses:pytest tests --ignore-glob='tests/test_framework_*.py'): 337 passed.tests/test_framework_langchain.py32 passed, 2 failed. Those 2 are the ones.github/python-tests-known-broken.txtlists (dependency count, aset_attributescall).Version overlap with #281 (base
main, bumps the same package to 1.1.1): the two PRs conflict inpython/pyproject.tomlandpython/CHANGELOG.md. Whichever merges second sets the version in all three files (pyproject.toml,CHANGELOG.md,fi_instrumentation/instrumentation/version.py): 1.2.0 if this PR is second, 1.2.1 for #281 if it is second. Nothing here is on PyPI yet (fi-instrumentation-otel 1.1.0, traceAI-langchain 0.2.0, traceAI-autogen 0.2.0 are the latest).