From 811a590d4793eda4d76524e0bbf675e5ffa78d5b Mon Sep 17 00:00:00 2001 From: CreatorGhost Date: Sun, 12 Jul 2026 02:05:09 +0530 Subject: [PATCH 1/2] fix(opencode): create root span per prompt for OTEL trace isolation Ported from upstream anomalyco/opencode#36179. --- packages/opencode/src/session/prompt.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 6f16f6879dc5..b2d911ba5ddf 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1358,11 +1358,19 @@ const layer = Layer.effect( }, ) - const loop: (input: LoopInput) => Effect.Effect = Effect.fn("SessionPrompt.loop")(function* ( - input: LoopInput, - ) { - return yield* state.ensureRunning(input.sessionID, lastAssistant(input.sessionID), runLoop(input.sessionID)) - }) + const loop: (input: LoopInput) => Effect.Effect = (input: LoopInput) => + state + .ensureRunning(input.sessionID, lastAssistant(input.sessionID), runLoop(input.sessionID)) + .pipe( + Effect.withSpan("invoke_agent", { + root: true, + attributes: { + "gen_ai.operation.name": "invoke_agent", + "gen_ai.conversation.id": input.sessionID, + "session.id": input.sessionID, + }, + }), + ) const shell: (input: ShellInput) => Effect.Effect = Effect.fn( "SessionPrompt.shell", From feecef43377f66bcabb5a04381069bb0b33eaf18 Mon Sep 17 00:00:00 2001 From: CreatorGhost Date: Sun, 12 Jul 2026 21:55:14 +0530 Subject: [PATCH 2/2] fix(opencode): attach invoke_agent root span to forked work Addresses Opus review of PR #31: the root span wrapped the ensureRunning caller, but ensureRunning may store work and start it later from a prior run's fiber, so queued/steered prompts got child spans mis-parented under the previous prompt's trace and the span measured queue-wait instead of the agent turn. Wrap runLoop (the forked work) instead, and keep the named SessionPrompt.loop fn. --- packages/opencode/src/session/prompt.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index b2d911ba5ddf..1b11e85b14a4 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1358,10 +1358,18 @@ const layer = Layer.effect( }, ) - const loop: (input: LoopInput) => Effect.Effect = (input: LoopInput) => - state - .ensureRunning(input.sessionID, lastAssistant(input.sessionID), runLoop(input.sessionID)) - .pipe( + const loop: (input: LoopInput) => Effect.Effect = Effect.fn("SessionPrompt.loop")(function* ( + input: LoopInput, + ) { + // Wrap the forked work (runLoop) — not the ensureRunning caller — so every + // prompt (idle or queued/steered) gets its own root trace and its child spans + // are parented correctly. ensureRunning may store `work` and start it later + // from a prior run's fiber, so a span on the caller would mis-parent queued + // prompts and measure queue-wait instead of the agent turn. + return yield* state.ensureRunning( + input.sessionID, + lastAssistant(input.sessionID), + runLoop(input.sessionID).pipe( Effect.withSpan("invoke_agent", { root: true, attributes: { @@ -1370,7 +1378,9 @@ const layer = Layer.effect( "session.id": input.sessionID, }, }), - ) + ), + ) + }) const shell: (input: ShellInput) => Effect.Effect = Effect.fn( "SessionPrompt.shell",