fix(providers): thread opencode traceparent per call - #10622
Conversation
There was a problem hiding this comment.
👍 All Clear
I reviewed the changes adding per-traceparent server restarts and temporary OPENCODE_TRACEPARENT propagation in the OpenCode SDK provider, plus related docs and tests. The modifications affect server lifecycle and telemetry only and do not alter prompt construction, tool permissions, or output handling paths. Based on the diff, no new LLM security risks were introduced.
Minimum severity threshold: 🟡 Medium | To re-scan after changes, comment @promptfoo-scanner
Learn more
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38737843a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return await this.runSerializedServerLifecycleCall( | ||
| config.restart_server_per_call, |
There was a problem hiding this comment.
Disable cache reads for per-trace server restarts
When caching is enabled and a matching response already exists, getCachedResponse returns before this lifecycle block runs, so no server is started or retagged with the current traceparent; collectExternalTraceAfterProviderCall also explicitly skips fetching external traces for cached responses. Consequently, the documented trajectory:* use case can receive no trace evidence and produce incorrect assertion results on repeated prompts unless the user happens to pass --no-cache. Disable response caching whenever restart_server_per_call is active.
AGENTS.md reference: AGENTS.md:L370-L372
Useful? React with 👍 / 👎.
| await this.waitForPreviousSessionCall(previous, abortSignal); | ||
| return await run(); | ||
| } finally { | ||
| release(); |
There was a problem hiding this comment.
Preserve the mutex when a queued call is aborted
If call A is running, call B is waiting with its own abort signal, and call C queues behind B, aborting B makes waitForPreviousSessionCall reject and this finally resolves B's queue promise even though A still owns the lifecycle lock. C can then enter concurrently, see a different traceparent, and close A's active server mid-prompt. An aborted waiter must keep subsequent callers chained to its predecessor rather than releasing them immediately.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Reset tagged servers when restart mode is overridden
Because prepareCall merges context.prompt.config, one prompt can enable restart_server_per_call even when the provider default is false, leaving the shared client tagged with that prompt's traceparent. A later prompt that omits or disables the flag skips this guard, reuses the tagged client, and emits its OpenCode spans under the earlier test's trace. Either make this lifecycle option provider-level-only or restart an already-tagged client whenever the incoming call is not using the same trace context.
AGENTS.md reference: AGENTS.md:L370-L372
Useful? React with 👍 / 👎.

Summary
restart_server_per_callmode foropencode:sdkso promptfoo-owned OpenCode servers restart when the evaltraceparentchanges.OPENCODE_TRACEPARENTonly while spawning OpenCode, matching the current SDK behavior where the server inheritsprocess.envat spawn time.baseUrlandpersist_sessionscombinations, and document the trajectory assertion tradeoff.Fixes #10518.
Why
OpenCode telemetry plugins that read trace context at process startup cannot correlate per-test spans today because
opencode:sdkkeeps one owned server alive across calls and never forwardscontext.traceparent. That makestrajectory:*assertions unreliable for OpenCode runs.Validation
npx vitest run test/providers/opencode-sdk.test.ts- 139 passednpx @biomejs/biome check src/providers/opencode-sdk.ts test/providers/opencode-sdk.test.tsnpx prettier --check site/docs/providers/opencode-sdk.mdgit diff --checkAlso ran
npm run tsc; it is currently blocked on unrelated existingsrc/providers/openai/codex-security.tserrors because@openai/codex-securityis not available in this local checkout.I could not run a real OpenCode + OTLP e2e locally because this machine does not have the
opencodeCLI on PATH. The provider lifecycle is covered with the existing mocked OpenCode SDK suite, including restart, env injection/restoration, default no-op behavior, and incompatible config rejection.