Repository navigation
DurableAgent experimental_telemetry does not emit AI SDK spans for LLM or tool calls #1296
Description
Summary
@workflow/ai DurableAgent accepts experimental_telemetry, but durable agent turns do not emit the expected AI SDK telemetry spans (ai.streamText, ai.streamText.doStream, ai.toolCall).
In the same app, plain AI SDK streamText() calls emit Langfuse/OpenTelemetry spans correctly. Only the durable workflow path is missing.
Expected behavior
When experimental_telemetry: { isEnabled: true, functionId, metadata } is passed to DurableAgent, the durable execution path should emit the same AI SDK telemetry shape developers get from streamText() / generateText(), including:
ai.streamTextai.streamText.doStreamai.toolCall
This should work with standard OpenTelemetry setups such as @vercel/otel + langfuse-vercel.
Actual behavior
DurableAgent stores and forwards telemetry config, but the internal execution path appears to bypass AI SDK telemetry wrappers:
DurableAgentstoresexperimental_telemetrystreamTextIteratorforwards it intodoStreamStepdoStreamStepthen calls rawmodel.doStream(callOptions)without applying telemetry- durable tool execution also bypasses AI SDK
ai.toolCalltracing helpers
Result:
- plain
streamText()spans show up - durable workflow turns do not create observations/spans in Langfuse
Reproduction
- Next.js app with
instrumentation.tsusingregisterOTel({ traceExporter: new LangfuseExporter() }) - Verify a normal
streamText()call emits spans in Langfuse - Create a
DurableAgentwithexperimental_telemetry: { isEnabled: true, functionId: 'my-agent' } - Run
agent.stream(...)inside a workflow with tool calls - Observe that planner / plain AI SDK traces appear, but durable main-turn spans do not
Why this seems to be an implementation bug
In the published package:
durable-agent.jsstores telemetry on the agent and forwards it duringstream()stream-text-iterator.jspasses telemetry intodoStreamStepdo-stream-step.jsperforms a rawmodel.doStream(...)and does not use the telemetry settingexecuteTool()indurable-agent.jsdoes not create AI SDK-styleai.toolCallspans
So telemetry is exposed in the API surface but not honored by the durable execution path.
What we need
Please make DurableAgent telemetry behavior match AI SDK core behavior.
Acceptable fixes would be:
- Route durable LLM execution through the same AI SDK telemetry wrappers used by
streamText()/generateText(), or - Add an internal telemetry implementation in
@workflow/aithat preserves the same span names/structure/attributes, includingai.toolCall, or - Expose an official helper from AI SDK / Workflow so DurableAgent can reuse the supported telemetry path instead of duplicating logic
Request for regression coverage
Please add a regression test that verifies DurableAgent emits telemetry spans when experimental_telemetry.isEnabled === true, including:
- outer generation span
- provider call span
- tool call span
- functionId / metadata propagation
Activity
pranaygp commentedon Mar 13, 2026
In #1362 we fixed how the options are wired through and added testing to track this gap so we can ensure it actually works correctly going forward
note that it's not yet actually implemented so I'm keeping this issue open
DurableAgent: type helpers, prepareStep on constructor, supportedUrls…
mattschaller commentedon Mar 14, 2026
Following this one too. Once the DurableAgent execution path properly emits spans, you'll likely run into the ai.* vs gen_ai.* attribute naming gap — the SDK uses ai.usage.inputTokens but most OTel backends expect the standard gen_ai.* semantic conventions. I built a vendor-neutral SpanProcessor called ai-sdk-otel-adapter that handles that remapping automatically. Might save some config pain once the spans start flowing.
craze3 commentedon Mar 21, 2026
Thanks for shipping #1385. I upgraded to the published release that includes it, but the core interoperability issue still seems unresolved for AI SDK telemetry consumers like
langfuse-vercel.As of March 21, 2026, I am on:
@workflow/ai@4.1.0-beta.57workflow@4.2.0-beta.71What improved:
ai.streamText/ai.streamText.doStream.What is still wrong:
streamText.input: undefined/output: undefinedinstead of the rich trace structure I got before moving to Workflow.The important gap seems to be that the released
DurableAgenttelemetry emits some span names and some model/gen_ai attributes, but not the full AI SDK-style telemetry attributes that downstream exporters expect.Specifically, I still do not see emitted attributes equivalent to:
ai.prompt.messagesai.prompt.toolsai.prompt.toolChoiceai.response.textai.response.finishReasonai.response.modelai.usage.*ai.toolCall.resultTool spans appear to include args, but not the tool result payload.
Why this matters:
langfuse-verceldoes not just key off span names. It reads AI SDK-style attributes likeai.prompt.messages,ai.response.text, andai.toolCall.resultto populate prompt/output/tool rendering.What I think the proper fix is:
DurableAgent/ Workflowexperimental_telemetryshould emit the same AI SDK telemetry schema as regular AI SDKstreamTextand tool execution, not just similarly named spans.finishevent.ai.toolCall.argsandai.toolCall.result.I do not think this needs a Langfuse-specific integration. AI SDK telemetry parity should be enough for existing OTel exporters/adapters to work again without app-level patches.
@VaguelySerious @pranaygp can you please reopen the issue? I think this is important. Advanced workflows are impossible to get right without proper tracing.
VaguelySerious commentedon Apr 3, 2026
(AI) Reproduction
Confirmed by code inspection.
doStreamStepwrapped onlymodel.doStream()in the telemetry span, so the span closed before the stream was consumed — usage, finish reason, response text, and prompt data were never recorded.executeToolsimilarly omittedai.toolCall.result. These gaps explain why Langfuse showsinput: undefined/output: undefineddespite span names being correct.Related issues
No duplicates found. PRs #1362 and #1385 partially addressed this by adding span creation and names, but did not populate response-time attributes.
Fix
#1608 adds full AI SDK-compatible telemetry attributes:
ai.streamText.doStreamspan now covers the entire stream lifecycle and recordsai.prompt.messages,ai.prompt.tools,ai.response.text,ai.response.finishReason,ai.usage.*,gen_ai.response.*,gen_ai.usage.*, and timingai.toolCallspan now recordsai.toolCall.resultai.streamTextspan wraps the full step iteration with aggregated usagerecordInputs/recordOutputsgating honored throughoutTo see if this fix solves your issue, could you try to install the pre-release in your package.json? Just replace the
workflowdep like so:{ "dependencies": { "workflow": "https://workflow-docs-7t3kulveh.vercel.sh/workflow.tgz", "@workflow/ai": "https://workflow-docs-7t3kulveh.vercel.sh/workflow-ai.tgz" } }craze3 commentedon Apr 5, 2026
@VaguelySerious It's working! I'm successfully getting the expected traces after runs.
I did see some inconsistency where, for some models, tool calls showed up only as
ai.streamText.doStreamrather than distinctai.toolCall.*spans (in Langfuse). For example, Kimi K2.5 reports all the spans as "doStream", even when they are tool calls like readFile and writeFile, whereas Minimax M2.7 (among other models) shows the correct tool names on each span.Thank you for all your hard work btw 🙏
VaguelySerious commentedon Apr 6, 2026
@craze3 Made some smaller changes to see if I can address the inconsistencies you're seeing. Could you give this a try?
{ "dependencies": { "workflow": "https://workflow-docs-8eop8l5bh.vercel.sh/workflow.tgz", "@workflow/ai": "https://workflow-docs-8eop8l5bh.vercel.sh/workflow-ai.tgz" } }craze3 commentedon Apr 7, 2026
@VaguelySerious I'm sorry but I'm not seeing much improvement. For example, I now see
readFiletool calls correctly where I previously sawdoStreams, but thosedoStreams still appear later at the bottom of the trace. I'm not sure if this is expected behavior or if they are detached or simply redundant. Happy to share more details on email/call. But I think this is a great improvement compared to the current implementation in the latest public release!VaguelySerious commentedon Apr 7, 2026
@craze3 Thanks, will ship this in the next release. Feel free to make PRs against this repository with any smaller improvements you'd like to see for telemetry!