otelMiddleware: media generation spans never capture prompt, input media or output, even with captureContent
メンテナーはふだん 1 日以内に返信
@AlemTuzlak がすでに取り組んでいます。
2026年9月27日 から。
評価
この issue はまだ評価されていません。
説明
Summary
otelMiddleware opens one CLIENT span for each media activity call (generateImage, generateVideo, generateAudio, generateSpeech, generateTranscription, …), added via #720. That span carries the provider, the model, the operation name and usage. It never records what was asked for or what came back, even with captureContent: true:
- no prompt
- no input media: reference images, start and end frames, source audio for transcription
- no output: generated image, video or audio URLs, or the transcript text
In PostHog, Langfuse or Datadog every media generation therefore shows up as an empty Input/Output pair with a cost attached. For image-to-video or reference-to-video, where the result depends mostly on the input images, there is nothing in the trace to debug from.
Root cause
startMediaSpan / endMediaSpan (packages/ai/src/middlewares/otel.ts:343–384) only set gen_ai.system, gen_ai.operation.name, gen_ai.request.model and usage. captureContent is only checked on the chat paths.
The inputs are already on the context: GenerationMiddlewareContext.artifactInputs holds the activity inputs. The media path never reads it, and the result is never inspected in the terminal hook.
The only workaround is attributeEnricher / onSpanEnd in every app, reimplementing the per-activity input and output shapes that the library already knows.
Proposal
When captureContent is on, the media span writes the same attributes the chat iteration spans do:
gen_ai.input.messages/langfuse.observation.input: the prompt as a text part, plus each input media reference as a URI part ({ type: 'uri', modality, uri }), reusing whatever part serialisation #1525 lands on.gen_ai.output.messages/langfuse.observation.output: output media URLs as URI parts, and transcript text as a text part.- Inline or base64 inputs and outputs follow the same rule as #1525: a placeholder by default, and an opt-in hook to swap in a URL.
redactandmaxContentLengthstill apply.
Related
- #720: added the media span (closed)
- #1525:
captureContentdrops non-text parts on chat spans
Version
@tanstack/ai 0.58.0 (current main has the same code).
I'm happy to open a PR.
- 主要言語
- TypeScript
- スター
- 3.1k
- フォーク
- 340
- 平均マージ
- 2日 10時間
- マージ済み PR(30日)
- 175
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
TanStack/ai のほかの issue
-
update elevenlabs対応中かも @tombeckenham が今日担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
メンテナーはふだん 1 日以内に返信
-
onAfterToolCall failure records a second, contradictory result for a successful server tool対応中かも @AlemTuzlak が今日担当しました。 オープンhas-pr waiting-on: maintainer
メンテナーはふだん 1 日以内に返信
-
SSE and NDJSON response streams drain unread sources without backpressure対応中かも @tombeckenham が今日担当しました。 オープンhas-pr waiting-on: maintainer
メンテナーはふだん 1 日以内に返信
-
Solid useChat drops earlier turns after a reactive request option changes対応中かも @AlemTuzlak が今日担当しました。 オープンhas-pr waiting-on: maintainer
メンテナーはふだん 1 日以内に返信
-
Tool calls from one model step run one at a time, but the docs say they run in parallel対応中かも @tombeckenham が 1 日前に担当しました。 オープンwaiting-on: maintainer
TanStack/ai#1547 · リアクション 1 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
priority: P2
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
prime-radiant-inc/evener#3291 ·
メンテナーはふだん 1 日以内に返信
-
accessibility bug revealjs
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
quarto-dev/quarto-cli#14961 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
supabase/agent-skills#614 ·
-
Content
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
RunestoneInteractive/rs#1559 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信