diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index 09a53efd3..6d0a78d4c 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -967,7 +967,7 @@ internal void RegisterHooks(SessionHooks hooks) JsonSerializer.Deserialize(input.GetRawText(), SessionJsonContext.Default.ErrorOccurredHookInput)!, invocation) : null, - _ => throw new ArgumentException($"Unknown hook type: {hookType}") + _ => null }; } diff --git a/go/session.go b/go/session.go index f7b4a852c..71facb03b 100644 --- a/go/session.go +++ b/go/session.go @@ -451,7 +451,7 @@ func (s *Session) handleHooksInvoke(hookType string, rawInput json.RawMessage) ( } return hooks.OnErrorOccurred(input, invocation) default: - return nil, fmt.Errorf("unknown hook type: %s", hookType) + return nil, nil } } diff --git a/go/session_test.go b/go/session_test.go index 75d5412ad..30b29e7a4 100644 --- a/go/session_test.go +++ b/go/session_test.go @@ -1,6 +1,7 @@ package copilot import ( + "encoding/json" "fmt" "strings" "sync" @@ -530,6 +531,45 @@ func TestSession_ElicitationHandler(t *testing.T) { }) } +func TestSession_HookForwardCompatibility(t *testing.T) { + t.Run("unknown hook type returns nil without error when known hooks are registered", func(t *testing.T) { + session, cleanup := newTestSession() + defer cleanup() + + // Register known hook handlers to simulate a real session configuration. + // The handler itself does nothing; it only exists to confirm that even + // when other hooks are active, an unknown hook type is still ignored. + session.registerHooks(&SessionHooks{ + OnPostToolUse: func(input PostToolUseHookInput, invocation HookInvocation) (*PostToolUseHookOutput, error) { + return nil, nil + }, + }) + + // "postToolUseFailure" is an example of a hook type introduced by a newer + // CLI version that the SDK does not yet know about. + output, err := session.handleHooksInvoke("postToolUseFailure", json.RawMessage(`{}`)) + if err != nil { + t.Errorf("Expected no error for unknown hook type, got: %v", err) + } + if output != nil { + t.Errorf("Expected nil output for unknown hook type, got: %v", output) + } + }) + + t.Run("unknown hook type with no hooks registered returns nil without error", func(t *testing.T) { + session, cleanup := newTestSession() + defer cleanup() + + output, err := session.handleHooksInvoke("futureHookType", json.RawMessage(`{"someField":"value"}`)) + if err != nil { + t.Errorf("Expected no error for unknown hook type with no hooks, got: %v", err) + } + if output != nil { + t.Errorf("Expected nil output for unknown hook type with no hooks, got: %v", output) + } + }) +} + func TestSession_ElicitationRequestSchema(t *testing.T) { t.Run("elicitation.requested passes full schema to handler", func(t *testing.T) { // Verify the schema extraction logic from handleBroadcastEvent