Add provider audit envelopes and user-input audit metadata#12
Merged
Conversation
Expose provider-native audit envelopes on surfaced message types and propagate audit metadata through requestUserInput parsing and response serialization. This keeps provider event capture SDK-owned while preserving the existing normalized public surface for downstream consumers.
Expose NewAuditEnvelope(eventType, subtype, payload) as a public API matching the OpenRouter SDK signature, enabling consumers to construct audit envelopes from typed payloads. The existing private parse-time constructor remains for raw wire data attachment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add WithMaxTurns option with exec CLI flag and app-server protocol support across both backends. Add MultiSelect field to user input Question struct with camelCase/snake_case parsing.
The audit envelope payload was previously produced by re-marshaling the decoded map[string]any, which loses byte-level details like number formatting (1e+06 vs 1000000), key ordering, and whitespace from the original wire data. This is problematic for audit/provenance use cases where exact reproduction of the provider response matters. Changes: - Add internal/message/raw_json.go with AnnotateRawJSON, extractRawJSON, and stripRawJSON helpers that thread original bytes through decoded maps via a hidden sentinel key. - Widen Parse() signature from map[string]any to any, accepting []byte and json.RawMessage directly so callers can pass raw wire data. - Thread raw line bytes through the JSON-RPC notification path (RPCNotification.Raw field, toNotification parameter) and annotate events in both AppServerAdapter and CLITransport before dispatch. - Update sessions.go GetSessionMessages to pass raw line bytes to Parse. - newAuditEnvelope now prefers the annotated original bytes, falling back to re-marshal only when raw bytes are unavailable. - Add test verifying audit payloads preserve original JSON bytes verbatim. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Message Extend ResultMessage with session-level metadata fields returned by the Codex turn-completed event: stop_reason (optional), duration_ms, num_turns, and total_cost_usd (optional). Parse these fields from the raw event map in parseCodexTurnCompleted and add tests covering full field presence, the Parse entry point, and missing optional field defaults. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…udit-cutover # Conflicts: # internal/subprocess/appserver_adapter.go
…easoning text Reasoning stream deltas (item/reasoning/textDelta, item/reasoning/summaryTextDelta) now emit as thinking_delta with a "thinking" key instead of text_delta with "text", allowing consumers to distinguish reasoning content from regular text output in the streaming path. Added reasoningTextByItem accumulator that collects streaming reasoning deltas per item ID. When item.completed arrives for a reasoning item with an empty summary array, the accumulated reasoning text is used as fallback, ensuring reasoning content is not lost. Added ensureDefaultModel helper to mark gpt-5.3-codex as the default model when the API model list does not flag any model with isDefault. Updated examples to handle thinking_delta events. Added comprehensive unit tests for delta accumulation, summary precedence, thinking delta emission, reasoning item parsing, and default model selection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bare `extended_thinking` pattern was matching examples/extended_thinking/, preventing the example source from being tracked. Prefix with `/` to only match the root-level binary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… wire format
Add full MCP elicitation support with typed request/response structures,
callback dispatch, and auto-decline behavior when no callback is set.
The previous stub unconditionally auto-accepted; now the flow properly
parses elicitation fields (mode, URL, schema, elicitation ID) and routes
through the OnElicitation callback.
Fix HandlePermissionsApproval to return {permissions, scope: "turn"}
instead of {decision: "accept"/"decline"}, matching the actual app-server
protocol. Denied requests now return empty permissions with turn scope
rather than a "decline" decision string.
Register mcpServer_elicitation/request and item_permissions/requestApproval
as live handlers — these were previously tracked as stale/future request
types but are now present in the current codex schema.
- Add internal/elicitation package with Mode, Action, Request, Response types
- Add WithOnElicitation option and capability entry (exec: unsupported, app-server: supported)
- Re-export elicitation types and constants from root package
- Add comprehensive tests for elicitation (form, URL, no-callback, nil-response)
- Update permissions approval tests to assert new wire format
- Remove stale handler negative test that is no longer applicable
- Bump integration test timeout from 240s to 600s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mattevans
approved these changes
Apr 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Major feature additions, protocol fixes, and schema enforcement across the SDK.
Provider Audit Envelopes
AuditEnvelopetype (event_type,subtype,payload) attached to all message types (UserMessage,AssistantMessage,SystemMessage,ResultMessage,StreamEvent,TaskStartedMessage,TaskCompleteMessage,ThreadRolledBackMessage)AnnotateRawJSON/extractRawJSONhelpers (internal/message/raw_json.go)NewAuditEnvelope(eventType, subtype, payload)constructor for cross-SDK consistencyrequestUserInputparsing and response serializationMCP Elicitation Callback
WithOnElicitationoption and typedelicitation.Request/elicitation.Responsetypes (internal/elicitation/elicitation.go)formandurlelicitation modes with optional fields (ElicitationID,URL,RequestedSchema,TurnID)mcpServer_elicitation/requesthandler in session; auto-declines when no callback is setPermissions Approval Wire Format Fix
HandlePermissionsApprovalresponse format from{"decision": "accept"}to{"permissions": {...}, "scope": "turn"}matching current Codex app-server protocolitem_permissions/requestApprovalhandler (previously unregistered)"decline"stringReasoning / Thinking Delta Support
thinking_delta(nottext_delta) inStreamEventduring partial message streamingThinkingBlockcontent blocks on completedAssistantMessageappserver_adapter.goto map Codex reasoning items into SDK thinking typesextended_thinkingandinclude_partial_messagesexamples to handlethinking_deltaeventsTestPartialMessages_ThinkingDeltaDistinguishedResultMessage Enrichment
stop_reason,duration_ms,num_turns, andtotal_cost_usdfields toResultMessageresultand Codex-styleresponse.completedeventsWithMaxTurns Option
WithMaxTurns(n)option to limit conversation turnsexecbackend (--max-turnsCLI flag) andapp-serverbackend (maxTurnsinit payload)MultiSelect Support for User Input
multiSelect/multi_selectfield on user input questionsMultiSelectfield touserinput.QuestiontypeSchema Enforcement (Structured Output)
internal/schema/enforce.gowithEnforceStrictModeandEnforceAdditionalPropertiesadditionalProperties: falseand ensurerequiredlists all property keys on every object node (OpenAI strict structured-output compliance)$defs,anyOf, and arrayitemsextractOutputSchemaduring session initializationFixes & Maintenance
.gitignore: scopeextended_thinkingto root-only match (/extended_thinking)budget_stderr_test.gostderr callback with mutextest_examples.shto handle examples with their owngo.mod(nested modules)TestSessionRegisterHandlers_DoesNotRegisterRequestTypesMissingFromCurrentCodexSchemamcpServer/elicitation/requestanditem/permissions/requestApprovalto positive handler coverage testFiles Changed (30 files, +1867 / -120)
options.go,types.go,sessions.gointernal/message/message.go,internal/message/parse.go,internal/message/raw_json.go,internal/message/parse_test.gointernal/elicitation/elicitation.gointernal/protocol/session.go,internal/protocol/session_test.go,internal/protocol/session_integration_test.gointernal/schema/enforce.go,internal/schema/enforce_test.gointernal/config/options.go,internal/config/capability.gointernal/cli/command.go,internal/cli/cli_test.gointernal/userinput/userinput.gointernal/subprocess/appserver.go,internal/subprocess/appserver_adapter.go,internal/subprocess/appserver_adapter_test.go,internal/subprocess/cli.go,internal/subprocess/jsonrpc.goexamples/extended_thinking/main.go,examples/include_partial_messages/main.gointegration/budget_stderr_test.go,integration/streaming_test.goMakefile,.gitignore,scripts/test_examples.shTest plan
go test ./...passesgo test -race ./...passesNewAuditEnvelopeconstructor round-trip and marshal error testsresultandresponse.completedeventsWithMaxTurnsCLI flag and init payload testsEnforceStrictMode/EnforceAdditionalPropertiesunit tests (nested, $defs, anyOf, items)🤖 Generated with Claude Code