Skip to content

feat(contract): add captureRenderedPrompt opt-in + .promptRendered GenerationEvent#1884

Merged
roryford merged 1 commit into
mainfrom
feat/obs-prompt-rendered
Jun 15, 2026
Merged

feat(contract): add captureRenderedPrompt opt-in + .promptRendered GenerationEvent#1884
roryford merged 1 commit into
mainfrom
feat/obs-prompt-rendered

Conversation

@roryford

Copy link
Copy Markdown
Owner

Summary

  • Adds GenerationEvent.promptRendered(text:) — a new opt-in case that surfaces the fully-assembled prompt string as the first event in the generation stream.
  • Guards it behind GenerationConfig.captureRenderedPrompt: Bool = false (off by default) to prevent unintentional retention of sensitive prompt content.
  • Injects the event in GenerationQueue.dispatchToBackend by wrapping the backend stream on both the TokenCountingBackend preflight path and the standard non-template/template path.

What changed

Sources/ManifoldContract/GenerationEvent.swift

  • New case promptRendered(text: String) placed between prefillProgress and token.

Sources/ManifoldContract/InferenceBackend.swift

  • New public var captureRenderedPrompt: Bool = false on GenerationConfig. Runtime-only; excluded from Codable persistence like jsonMode and thinkingMarkers.

Sources/ManifoldInference/Services/GenerationQueue.swift

  • dispatchToBackend wraps the returned GenerationStream with a new prependingPromptRendered helper that yields .promptRendered before forwarding all upstream events when the opt-in is set.

Sources/ManifoldInference/Services/GenerationStreamConsumer.swift

  • Maps .promptRendered.ignore (advisory metadata, no chat-message state mutation — mirrors .throttleDiagnostic and .kvCacheReuse).

Exhaustive switch updates

  • BackendSeamConsumer (APIFreezeTests freeze tripwire)
  • EventRecorder (ManifoldFuzz)
  • ScenarioRunner (ManifoldTools)
  • eventKey helpers in ClaudeStreamEventExtractorTests, OllamaStreamEventExtractorTests, OpenAIStreamEventExtractorTests, OpenAIResponsesStreamEventExtractorTests (×2)
  • CloudThinkingTokenTests, OllamaToolCallLiveReplayTests, OpenAIResponsesBackendTests
  • ToolCallContractTests (×2), ParallelToolCallOrderingTests

Tests/ManifoldInferenceTests/PromptRenderedEventTests.swift (new)

  • test_captureRenderedPrompt_true_emitsPromptRenderedAsFirstEvent
  • test_captureRenderedPrompt_true_promptRenderedTextMatchesUserMessage
  • test_captureRenderedPrompt_true_tokenEventFollowsPromptRendered
  • test_captureRenderedPrompt_false_noPromptRenderedEvent
  • test_captureRenderedPrompt_explicitFalse_noPromptRenderedEvent
  • test_captureRenderedPrompt_true_emitsExactlyOnePromptRenderedEvent

Test plan

  • swift build --build-tests --traits Server,Macros — build complete, zero errors
  • scripts/test.sh --profile spike --spike-module ManifoldInferenceTests --skip-update — 2888 tests passed, 0 failures
  • BackendSeamConsumer exhaustive freeze tripwire compiles
  • New PromptRenderedEventTests covers opt-in/opt-out, ordering, and exactly-once semantics

Closes #1879

🤖 Generated with Claude Code

…nerationEvent

Adds `GenerationEvent.promptRendered(text:)` — an opt-in diagnostic event that
surfaces the fully-assembled prompt string to the consumer immediately before
the first token. Off by default via `GenerationConfig.captureRenderedPrompt:
Bool = false` to avoid unintentional retention of sensitive prompt content.

- `GenerationEvent` gains the new case between `prefillProgress` and `token`.
- `GenerationConfig` gains `captureRenderedPrompt: Bool = false` (runtime-only;
  excluded from Codable persistence like `jsonMode`/`thinkingMarkers`).
- `GenerationQueue.dispatchToBackend` wraps the backend stream to prepend the
  event on both the TokenCountingBackend (preflight) path and the standard
  non-template / template paths when opt-in is true.
- `GenerationStreamConsumer` maps `.promptRendered` to `.ignore` (advisory
  metadata, no chat-message state mutation).
- All exhaustive `switch` sites updated: `BackendSeamConsumer`, `EventRecorder`,
  `FixtureComparator`, extractor-test `eventKey` helpers, `ScenarioRunner`, and
  per-backend test files.
- `PromptRenderedEventTests` (XCTestCase, `ManifoldInferenceTests`) covers:
  opt-in fires event as first in stream, payload contains user message, token
  events follow, opt-out emits no event, event fires exactly once per turn.

Closes #1879

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@roryford roryford merged commit 4c523e9 into main Jun 15, 2026
11 checks passed
@roryford roryford deleted the feat/obs-prompt-rendered branch June 15, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose per-generation provenance as structured, re-streamable events

1 participant