Skip to content

Commit de45c8f

Browse files
Copilotbrunoborges
andcommitted
Rename EventErrorPolicy values: STOP→PROPAGATE, CONTINUE→SUPPRESS (Spring-style)
Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>
1 parent e3989c4 commit de45c8f

5 files changed

Lines changed: 70 additions & 61 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ session.setEventErrorHandler((event, exception) -> {
4141
```
4242

4343
#### EventErrorPolicy for Dispatch Control
44-
Added `EventErrorPolicy` enum to control whether event dispatch continues or stops when a handler throws an exception. The default policy is `CONTINUE` (existing behavior). Set `STOP` to short-circuit dispatch on the first error:
44+
Added `EventErrorPolicy` enum to control whether event dispatch continues or stops when a handler throws an exception. The default policy is `SUPPRESS` (existing behavior). Set `PROPAGATE` to stop dispatch on the first error:
4545

4646
```java
47-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
47+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
4848
```
4949

5050
The `EventErrorHandler` is always invoked regardless of the policy. When no error handler is set, exceptions are silently consumed (no logging).

‎src/main/java/com/github/copilot/sdk/CopilotSession.java‎

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public final class CopilotSession implements AutoCloseable {
9696
private final AtomicReference<UserInputHandler> userInputHandler = new AtomicReference<>();
9797
private final AtomicReference<SessionHooks> hooksHandler = new AtomicReference<>();
9898
private volatile EventErrorHandler eventErrorHandler;
99-
private volatile EventErrorPolicy eventErrorPolicy = EventErrorPolicy.CONTINUE;
99+
private volatile EventErrorPolicy eventErrorPolicy = EventErrorPolicy.SUPPRESS;
100100

101101
/**
102102
* Creates a new session with the given ID and RPC client.
@@ -200,10 +200,10 @@ public void setEventErrorHandler(EventErrorHandler handler) {
200200
* preceding listener throws an exception.
201201
*
202202
* <ul>
203-
* <li>{@link EventErrorPolicy#CONTINUE} (default) — dispatch to all remaining
204-
* listeners regardless of errors</li>
205-
* <li>{@link EventErrorPolicy#STOP} — stop dispatching after the first
206-
* error</li>
203+
* <li>{@link EventErrorPolicy#SUPPRESS} (default) — suppress the error and
204+
* dispatch to all remaining listeners regardless</li>
205+
* <li>{@link EventErrorPolicy#PROPAGATE} — propagate the error effect by
206+
* stopping dispatch after the first error</li>
207207
* </ul>
208208
*
209209
* <p>
@@ -214,14 +214,14 @@ public void setEventErrorHandler(EventErrorHandler handler) {
214214
* <b>Example:</b>
215215
*
216216
* <pre>{@code
217-
* // Opt-in to short-circuit on first error
218-
* session.setEventErrorPolicy(EventErrorPolicy.STOP);
217+
* // Opt-in to propagate errors (stop dispatch on first error)
218+
* session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
219219
* session.setEventErrorHandler(
220220
* (event, ex) -> logger.error("Handler failed, stopping dispatch: {}", ex.getMessage(), ex));
221221
* }</pre>
222222
*
223223
* @param policy
224-
* the error policy (default is {@link EventErrorPolicy#CONTINUE})
224+
* the error policy (default is {@link EventErrorPolicy#SUPPRESS})
225225
* @see EventErrorPolicy
226226
* @see #setEventErrorHandler(EventErrorHandler)
227227
* @since 1.0.8
@@ -465,9 +465,10 @@ public <T extends AbstractSessionEvent> Closeable on(Class<T> eventType, Consume
465465
* handler is invoked in its own try/catch block. Whether dispatch continues
466466
* after a handler error depends on the configured {@link EventErrorPolicy}:
467467
* <ul>
468-
* <li>{@link EventErrorPolicy#CONTINUE} (default) — remaining handlers still
468+
* <li>{@link EventErrorPolicy#SUPPRESS} (default) — remaining handlers still
469469
* execute</li>
470-
* <li>{@link EventErrorPolicy#STOP} — dispatch stops after the first error</li>
470+
* <li>{@link EventErrorPolicy#PROPAGATE} — dispatch stops after the first
471+
* error</li>
471472
* </ul>
472473
* <p>
473474
* The configured {@link EventErrorHandler} is always invoked (if set),
@@ -494,7 +495,7 @@ void dispatchEvent(AbstractSessionEvent event) {
494495
break; // error handler itself failed — stop regardless of policy
495496
}
496497
}
497-
if (eventErrorPolicy == EventErrorPolicy.STOP) {
498+
if (eventErrorPolicy == EventErrorPolicy.PROPAGATE) {
498499
break;
499500
}
500501
}

‎src/main/java/com/github/copilot/sdk/EventErrorPolicy.java‎

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@
1919
* continues after the error handler has been called.
2020
*
2121
* <p>
22+
* The naming follows the convention used by Spring Framework's
23+
* {@code TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER} and
24+
* {@code TaskUtils.LOG_AND_PROPAGATE_ERROR_HANDLER}.
25+
*
26+
* <p>
2227
* <b>Example:</b>
2328
*
2429
* <pre>{@code
25-
* // Default: continue dispatching despite errors
26-
* session.setEventErrorPolicy(EventErrorPolicy.CONTINUE);
30+
* // Default: suppress errors and continue dispatching
31+
* session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS);
2732
*
28-
* // Opt-in to short-circuit on first error
29-
* session.setEventErrorPolicy(EventErrorPolicy.STOP);
33+
* // Opt-in to propagate errors (stop dispatch on first error)
34+
* session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
3035
* }</pre>
3136
*
3237
* @see CopilotSession#setEventErrorPolicy(EventErrorPolicy)
@@ -36,18 +41,21 @@
3641
public enum EventErrorPolicy {
3742

3843
/**
39-
* Stop dispatching on first listener error.
44+
* Suppress errors and continue dispatching to remaining listeners (default).
4045
* <p>
41-
* When a handler throws an exception, no further handlers are invoked. The
42-
* configured {@link EventErrorHandler} is still called before dispatch stops.
46+
* When a handler throws an exception, remaining handlers still execute. The
47+
* configured {@link EventErrorHandler} is called for each error. This is
48+
* analogous to Spring's {@code LOG_AND_SUPPRESS_ERROR_HANDLER} behavior.
4349
*/
44-
STOP,
50+
SUPPRESS,
4551

4652
/**
47-
* Continue dispatching to remaining listeners despite errors (default).
53+
* Propagate the error effect by stopping dispatch on first listener error.
4854
* <p>
49-
* When a handler throws an exception, remaining handlers still execute. The
50-
* configured {@link EventErrorHandler} is called for each error.
55+
* When a handler throws an exception, no further handlers are invoked. The
56+
* configured {@link EventErrorHandler} is still called before dispatch stops.
57+
* This is analogous to Spring's {@code LOG_AND_PROPAGATE_ERROR_HANDLER}
58+
* behavior.
5159
*/
52-
CONTINUE
60+
PROPAGATE
5361
}

‎src/site/markdown/advanced.md‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -498,12 +498,12 @@ session.setEventErrorHandler(null);
498498

499499
### Event Error Policy
500500

501-
By default, the SDK continues dispatching to remaining handlers after an error
502-
(`EventErrorPolicy.CONTINUE`). You can opt in to **short-circuit** behavior so
503-
that the first handler error stops dispatch:
501+
By default, the SDK suppresses errors and continues dispatching to remaining
502+
handlers (`EventErrorPolicy.SUPPRESS`). You can opt in to **propagate** errors
503+
so that the first handler error stops dispatch:
504504

505505
```java
506-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
506+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
507507
```
508508

509509
The `EventErrorHandler` (if set) is always invoked regardless of the policy —
@@ -512,26 +512,26 @@ handler returns.
512512

513513
| Policy | Behavior |
514514
|---|---|
515-
| `CONTINUE` (default) | All remaining handlers execute despite errors |
516-
| `STOP` | Dispatch halts after the first handler error |
515+
| `SUPPRESS` (default) | Suppress the error; all remaining handlers execute |
516+
| `PROPAGATE` | Propagate the error effect; dispatch halts after the first error |
517517

518518
You can combine both for full control:
519519

520520
```java
521-
// Log errors and stop dispatch on first failure
522-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
521+
// Log errors and propagate (stop dispatch on first failure)
522+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
523523
session.setEventErrorHandler((event, ex) ->
524524
logger.error("Handler failed, stopping: {}", ex.getMessage(), ex));
525525
```
526526

527527
Or switch policies dynamically:
528528

529529
```java
530-
// Start lenient
531-
session.setEventErrorPolicy(EventErrorPolicy.CONTINUE);
530+
// Start lenient (suppress errors)
531+
session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS);
532532

533-
// Later, switch to strict mode
534-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
533+
// Later, switch to strict mode (propagate errors)
534+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
535535
```
536536

537537
See [EventErrorPolicy](apidocs/com/github/copilot/sdk/EventErrorPolicy.html) and [EventErrorHandler](apidocs/com/github/copilot/sdk/EventErrorHandler.html) Javadoc for details.

‎src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java‎

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -556,19 +556,19 @@ void testDefaultPolicyContinuesOnError() {
556556

557557
dispatchEvent(createAssistantMessageEvent("Test"));
558558

559-
// All handlers should have been called (CONTINUE is default)
559+
// All handlers should have been called (SUPPRESS is default)
560560
assertEquals(1, handler1Called.get());
561561
assertEquals(1, handler2Called.get());
562562
assertEquals(1, handler3Called.get());
563563
}
564564

565565
@Test
566-
void testStopPolicyStopsOnFirstError() {
566+
void testPropagatePolicyStopsOnFirstError() {
567567
var handler1Called = new AtomicInteger(0);
568568
var handler2Called = new AtomicInteger(0);
569569
var errorHandlerCalls = new AtomicInteger(0);
570570

571-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
571+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
572572
session.setEventErrorHandler((event, exception) -> {
573573
errorHandlerCalls.incrementAndGet();
574574
});
@@ -586,17 +586,17 @@ void testStopPolicyStopsOnFirstError() {
586586

587587
dispatchEvent(createAssistantMessageEvent("Test"));
588588

589-
// Only one handler should have been called (STOP policy)
589+
// Only one handler should have been called (PROPAGATE policy)
590590
assertEquals(1, errorHandlerCalls.get());
591591
int totalCalls = handler1Called.get() + handler2Called.get();
592-
assertEquals(1, totalCalls, "Only one handler should execute with STOP policy");
592+
assertEquals(1, totalCalls, "Only one handler should execute with PROPAGATE policy");
593593
}
594594

595595
@Test
596-
void testStopPolicyErrorHandlerAlwaysInvoked() {
596+
void testPropagatePolicyErrorHandlerAlwaysInvoked() {
597597
var errorHandlerCalls = new AtomicInteger(0);
598598

599-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
599+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
600600
session.setEventErrorHandler((event, exception) -> {
601601
errorHandlerCalls.incrementAndGet();
602602
});
@@ -607,16 +607,16 @@ void testStopPolicyErrorHandlerAlwaysInvoked() {
607607

608608
dispatchEvent(createAssistantMessageEvent("Test"));
609609

610-
// Error handler should be called even with STOP policy
610+
// Error handler should be called even with PROPAGATE policy
611611
assertEquals(1, errorHandlerCalls.get());
612612
}
613613

614614
@Test
615-
void testContinuePolicyWithMultipleErrors() {
615+
void testSuppressPolicyWithMultipleErrors() {
616616
var errorHandlerCalls = new AtomicInteger(0);
617617
var successfulHandlerCalls = new AtomicInteger(0);
618618

619-
session.setEventErrorPolicy(EventErrorPolicy.CONTINUE);
619+
session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS);
620620
session.setEventErrorHandler((event, exception) -> {
621621
errorHandlerCalls.incrementAndGet();
622622
});
@@ -660,29 +660,29 @@ void testSwitchPolicyDynamically() {
660660
throw new RuntimeException("error");
661661
});
662662

663-
// With CONTINUE, both should fire
664-
session.setEventErrorPolicy(EventErrorPolicy.CONTINUE);
663+
// With SUPPRESS, both should fire
664+
session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS);
665665
dispatchEvent(createAssistantMessageEvent("Test1"));
666666
assertEquals(1, handler1Called.get());
667667
assertEquals(1, handler2Called.get());
668668

669669
handler1Called.set(0);
670670
handler2Called.set(0);
671671

672-
// Switch to STOP — only one should fire
673-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
672+
// Switch to PROPAGATE — only one should fire
673+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
674674
dispatchEvent(createAssistantMessageEvent("Test2"));
675675
int totalCalls = handler1Called.get() + handler2Called.get();
676-
assertEquals(1, totalCalls, "Only one handler should execute after switching to STOP");
676+
assertEquals(1, totalCalls, "Only one handler should execute after switching to PROPAGATE");
677677
}
678678

679679
@Test
680-
void testStopPolicyNoErrorHandlerSilentlyStops() {
680+
void testPropagatePolicyNoErrorHandlerSilentlyStops() {
681681
var handler1Called = new AtomicInteger(0);
682682
var handler2Called = new AtomicInteger(0);
683683

684-
// No error handler set, STOP policy
685-
session.setEventErrorPolicy(EventErrorPolicy.STOP);
684+
// No error handler set, PROPAGATE policy
685+
session.setEventErrorPolicy(EventErrorPolicy.PROPAGATE);
686686

687687
session.on(AssistantMessageEvent.class, msg -> {
688688
handler1Called.incrementAndGet();
@@ -696,9 +696,9 @@ void testStopPolicyNoErrorHandlerSilentlyStops() {
696696

697697
assertDoesNotThrow(() -> dispatchEvent(createAssistantMessageEvent("Test")));
698698

699-
// STOP policy should stop after first error, even without error handler
699+
// PROPAGATE policy should stop after first error, even without error handler
700700
int totalCalls = handler1Called.get() + handler2Called.get();
701-
assertEquals(1, totalCalls, "Only one handler should execute with STOP policy and no error handler");
701+
assertEquals(1, totalCalls, "Only one handler should execute with PROPAGATE policy and no error handler");
702702
}
703703

704704
@Test
@@ -711,8 +711,8 @@ void testErrorHandlerThrowingStopsRegardlessOfPolicy() {
711711
sessionLogger.setLevel(Level.OFF);
712712

713713
try {
714-
// CONTINUE policy, but error handler throws
715-
session.setEventErrorPolicy(EventErrorPolicy.CONTINUE);
714+
// SUPPRESS policy, but error handler throws
715+
session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS);
716716
session.setEventErrorHandler((event, exception) -> {
717717
throw new RuntimeException("error handler broke");
718718
});
@@ -729,10 +729,10 @@ void testErrorHandlerThrowingStopsRegardlessOfPolicy() {
729729

730730
assertDoesNotThrow(() -> dispatchEvent(createAssistantMessageEvent("Test")));
731731

732-
// Error handler threw — should stop regardless of CONTINUE policy
732+
// Error handler threw — should stop regardless of SUPPRESS policy
733733
int totalCalls = handler1Called.get() + handler2Called.get();
734734
assertEquals(1, totalCalls,
735-
"Only one handler should execute when error handler throws, even with CONTINUE policy");
735+
"Only one handler should execute when error handler throws, even with SUPPRESS policy");
736736
} finally {
737737
sessionLogger.setLevel(originalLevel);
738738
}

0 commit comments

Comments
 (0)