feat(extension): add provider lifecycle hooks#45
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a provider-request hook pipeline: CompletionRequest observe/mutate hooks, lifecycle before_provider_request provider_request mutations (payload + non-sensitive headers), header redaction/validation, provider-client wiring, tests, and updated docs. ChangesProvider Request Hook System
Sequence Diagram (high-level request flow)sequenceDiagram
participant Runtime
participant ExtensionManager
participant ProviderClient
Runtime->>ExtensionManager: dispatch before_provider_request (payload, redacted headers)
ExtensionManager->>Runtime: return mutated payload + provider_request.headers
Runtime->>ProviderClient: POST with providerRequest.Payload and providerRequest.Headers
ProviderClient->>Runtime: provider response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #45 +/- ##
==========================================
+ Coverage 60.72% 61.48% +0.75%
==========================================
Files 172 173 +1
Lines 16928 17073 +145
==========================================
+ Hits 10280 10497 +217
+ Misses 5624 5526 -98
- Partials 1024 1050 +26
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/assistant/openai_responses.go`:
- Around line 44-55: The headers map is reused across iterations and can be
mutated by applyProviderRequestHook, causing leakage between provider calls;
before calling applyProviderRequestHook in the loop, make a shallow copy of the
headers map (e.g., clone the original headers into a new map) and pass that
cloned map so applyProviderRequestHook and subsequent providerRequest.Headers
are isolated per iteration; ensure client.requestResponses continues to receive
providerRequest.Headers (the cloned, hook-modified map) and that no references
to the shared headers map are reused after the call.
In `@internal/assistant/provider_payload_hook_internal_test.go`:
- Around line 25-33: The handler currently calls require.NoError(t, ...) inside
the httptest http.HandlerFunc and writes to shared variables requestHeader and
requestBody without synchronization; instead capture any decode/write error and
the request data inside the handler and send them back to the test goroutine
(e.g., via a channel or sync.WaitGroup + mutex) so assertions like
require.NoError(t, err) and checks of requestHeader/requestBody happen in the
test goroutine; update the handler used with httptest.NewServer to avoid FailNow
from the handler goroutine and synchronize access to requestHeader/requestBody
before performing assertions.
In `@internal/extension/lifecycle.go`:
- Around line 162-165: The code currently overwrites result.ProviderRequest for
each handler (using providerRequestValue and providerRequestMutationFromLua),
causing earlier provider_request.headers to be lost; change the logic so when
providerRequestMutationFromLua returns a providerRequest, you merge its headers
into result.ProviderRequest.Headers (preserving existing header keys and
combining or appending values per your header semantics) and only set non-header
fields on result.ProviderRequest if they are not already present or should be
replaced; update the handling around
providerRequestValue/providerRequestMutationFromLua and result.ProviderRequest
to perform a shallow merge of structs and a deep merge of the headers map so
multiple lifecycle handlers compose correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ea18fe65-1c48-45de-99df-9176260add35
📒 Files selected for processing (17)
docs/extension-api.mdinternal/assistant/anthropic.gointernal/assistant/anthropic_internal_test.gointernal/assistant/client.gointernal/assistant/context_build.gointernal/assistant/lifecycle.gointernal/assistant/openai_chat.gointernal/assistant/openai_responses.gointernal/assistant/provider_hooks.gointernal/assistant/provider_hooks_internal_test.gointernal/assistant/provider_payload_hook_internal_test.gointernal/assistant/runtime.gointernal/assistant/runtime_events.gointernal/assistant/runtime_lifecycle_test.gointernal/extension/lifecycle.gointernal/extension/lifecycle_test.gointernal/extension/lua_values.go
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
internal/extension/lifecycle.go (1)
168-181: 💤 Low valueConsider grouping consecutive same-type parameters.
The function signature can be simplified by grouping the parameters of the same type, which is idiomatic Go style.
♻️ Suggested refactor
-func mergeProviderRequestMutation( - base ProviderRequestMutation, - override ProviderRequestMutation, -) ProviderRequestMutation { +func mergeProviderRequestMutation(base, override ProviderRequestMutation) ProviderRequestMutation { merged := ProviderRequestMutation{Headers: map[string]string{}} for key, value := range base.Headers { merged.Headers[key] = value🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/extension/lifecycle.go` around lines 168 - 181, The function mergeProviderRequestMutation uses two consecutive parameters of the same type; change the signature to group them as "base, override ProviderRequestMutation" (keeping the return type and function body unchanged), update any callers if needed, and leave the logic inside mergeProviderRequestMutation (merging Headers into merged) as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/assistant/provider_tool_calls_test.go`:
- Around line 96-120: The test currently uses input.Attempt and asserts "1"
twice which can pass if the hook is only invoked once and reused; update the
request.OnProviderRequest hook to record each invocation (e.g., append
input.Attempt to a local slice or increment a local counter) and return
iteration specific headers/payload, then after calling
NewHTTPCompletionClient().completeOpenAIResponses(...) assert that the recorded
invocations show 1 then 2 (and that captures/headers/payloads reflect attempt 1
and attempt 2) to prove the hook runs per request; locate and modify the
request.OnProviderRequest closure, the captures channel checks, and the
assertions around first/second to expect "1" then "2" and corresponding
iteration values.
---
Nitpick comments:
In `@internal/extension/lifecycle.go`:
- Around line 168-181: The function mergeProviderRequestMutation uses two
consecutive parameters of the same type; change the signature to group them as
"base, override ProviderRequestMutation" (keeping the return type and function
body unchanged), update any callers if needed, and leave the logic inside
mergeProviderRequestMutation (merging Headers into merged) as-is.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5ccd6b48-caf0-45d3-8c1c-78b0167774c5
📒 Files selected for processing (7)
internal/assistant/openai_responses.gointernal/assistant/provider_hooks.gointernal/assistant/provider_hooks_internal_test.gointernal/assistant/provider_payload_hook_internal_test.gointernal/assistant/provider_tool_calls_test.gointernal/extension/lifecycle.gointernal/extension/lifecycle_test.go
f9536bb to
63cbda0
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/assistant/provider_hooks.go`:
- Around line 59-60: The function currently returns raw errors from the provider
hook call (request.OnProviderRequest) — capture the returned error, and if
non-nil wrap it with samber/oops using the assistant domain and a descriptive
code (e.g. oops.In("assistant").Code("hook_failure").Wrapf(err, "provider hook
OnProviderRequest failed")) before returning; apply the same pattern to the
other raw error returns around the same file (the block at lines ~79-83) so all
hook/lifecycle errors are wrapped with
oops.In("assistant").Code(...).Wrapf(...).
In `@internal/assistant/runtime.go`:
- Around line 827-830: The code currently wires both OnProviderObserve ->
runtime.emitProviderRequest and OnProviderRequest ->
runtime.dispatchProviderRequestHook which causes before_provider_request
handlers to run twice; fix by keeping a single dispatch path: either remove the
OnProviderObserve binding to runtime.emitProviderRequest or modify
emitProviderRequest so it only observes and does not dispatch lifecycle events,
and retain runtime.dispatchProviderRequestHook on OnProviderRequest as the sole
dispatcher; update references to runtime.emitProviderRequest and
runtime.dispatchProviderRequestHook accordingly to ensure
before_provider_request is invoked exactly once per provider call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: eab40fcb-6da1-44ca-8e33-4ae91712e37f
📒 Files selected for processing (18)
docs/extension-api.mdinternal/assistant/anthropic.gointernal/assistant/anthropic_internal_test.gointernal/assistant/client.gointernal/assistant/context_build.gointernal/assistant/lifecycle.gointernal/assistant/openai_chat.gointernal/assistant/openai_responses.gointernal/assistant/provider_hooks.gointernal/assistant/provider_hooks_internal_test.gointernal/assistant/provider_payload_hook_internal_test.gointernal/assistant/provider_tool_calls_test.gointernal/assistant/runtime.gointernal/assistant/runtime_events.gointernal/assistant/runtime_lifecycle_test.gointernal/extension/lifecycle.gointernal/extension/lifecycle_test.gointernal/extension/lua_values.go
✅ Files skipped from review due to trivial changes (1)
- docs/extension-api.md
|



Summary
Validation