generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 33
Closed
Milestone
Description
Re-implement conversation-manager as a hook provider
Overview
Refactor the conversation-manager from a concrete class hierarchy to a hook-based system. This decouples conversation management from the Agent implementation and makes it consistent with the extensibility patterns in the SDK.
Note: This differs from the Python implementation approach.
Original Requirements
- Update AfterModelCall to pass in an exception if there is an exception
- Expose a AfterModelCall.retryModelCall that can be set to True/False (only valid if there's an exception)
- Reimplement all conversation-managers to be hook providers. The NullProvider simply registers 0 hooks
- Remove all hard-coded calls to the conversation manager and remove the base interface for the conversation manager. The existing apply/reduceContext should be simply hook callback messages
Implementation Requirements
Technical Approach
This is a breaking change that removes the ConversationManager abstract base class and converts conversation management to use the hooks system.
Current Implementation Context
- ConversationManager: Abstract base class with
applyManagement()andreduceContext()methods - Implementations:
NullConversationManagerandSlidingWindowConversationManager - Agent Integration: Direct method calls at:
- Line 286:
this.conversationManager.applyManagement(this)in finally block - Line 369:
this.conversationManager.reduceContext(this, error)on ContextWindowOverflowError
- Line 286:
- Public API: ConversationManager is exported and used in
AgentConfig.conversationManager
Changes Required
1. Update AfterModelCallEvent (src/hooks/events.ts)
- Add
retryModelCall?: booleanfield toAfterModelCallEventclass - This field is only valid when
errorfield is present - Hook callbacks can set this field to request a retry:
event.retryModelCall = true - Document that this enables hooks to trigger model call retry after reducing context
2. Convert NullConversationManager to HookProvider (src/conversation-manager/null-conversation-manager.ts)
- Change from
extends ConversationManagertoimplements HookProvider - Implement
registerCallbacks(registry: HookRegistry): voidmethod - Register 0 hooks (empty implementation - no callbacks registered)
- Remove
applyManagement()andreduceContext()methods - Update TSDoc to reflect it's a no-op HookProvider
3. Convert SlidingWindowConversationManager to HookProvider (src/conversation-manager/sliding-window-conversation-manager.ts)
- Change from
extends ConversationManagertoimplements HookProvider - Implement
registerCallbacks(registry: HookRegistry): voidmethod that registers:- AfterInvocationEvent callback: Calls logic from current
applyManagement()method - AfterModelCallEvent callback: When
erroris present, calls logic from currentreduceContext()method and setsevent.retryModelCall = trueif successful
- AfterInvocationEvent callback: Calls logic from current
- Keep existing private helper methods (
truncateToolResults,findLastMessageWithToolResults, etc.) - Keep
SlidingWindowConversationManagerConfiginterface unchanged - Maintain all existing behavior, just triggered via hooks instead of direct calls
4. Update Agent Class (src/agent/agent.ts)
- Remove
conversationManagerfield - Remove
conversationManagerfromAgentConfigtype - Remove line 286:
this.conversationManager.applyManagement(this)call (now handled by AfterInvocationEvent hook) - Update lines 361-374 (error handling in invokeModel):
// Current code: catch (error) { const modelError = normalizeError(error) await this.hooks.invokeCallbacks(new AfterModelCallEvent({ agent: this, error: modelError })) if (error instanceof ContextWindowOverflowError) { this.conversationManager.reduceContext(this, error) return yield* this.invokeModel(args) } throw error } // New code: catch (error) { const modelError = normalizeError(error) const event = await this.hooks.invokeCallbacks( new AfterModelCallEvent({ agent: this, error: modelError }) ) if (event.retryModelCall) { return yield* this.invokeModel(args) } throw error }
- Update constructor to remove default
SlidingWindowConversationManagerinitialization - Update TSDoc to reflect removal of conversationManager config
5. Remove ConversationManager Base Class
- Delete
src/conversation-manager/conversation-manager.ts - Update
src/conversation-manager/index.ts:- Remove exports for
ConversationManagerandConversationContext - Keep exports for
NullConversationManagerandSlidingWindowConversationManager
- Remove exports for
- Delete or minimize
src/conversation-manager/__tests__/conversation-manager.test.ts
6. Update Public API Exports (src/index.ts)
- Remove line 122:
export { ConversationManager } - Keep
export { NullConversationManager }(line 123) - Keep
export { SlidingWindowConversationManager, type SlidingWindowConversationManagerConfig }(lines 124-126)
7. Update Tests
- Update
src/conversation-manager/__tests__/null-conversation-manager.test.ts:- Test HookProvider interface implementation
- Test that registerCallbacks registers 0 hooks
- Update
src/conversation-manager/__tests__/sliding-window-conversation-manager.test.ts:- Test HookProvider interface implementation
- Test hook callbacks for AfterInvocationEvent and AfterModelCallEvent
- Test that retryModelCall is set correctly
- Test message trimming and truncation logic through hooks
- Update
src/agent/__tests__/agent.test.ts:- Remove tests for conversationManager field
- Add tests for retry behavior via retryModelCall flag
- Test that hooks properly trigger context management
- Maintain 80%+ test coverage across all modified files
Migration Guide for Users
Before (Old Pattern):
const agent = new Agent({
model,
conversationManager: new SlidingWindowConversationManager({ windowSize: 20 })
})After (New Pattern):
const agent = new Agent({
model,
hooks: [new SlidingWindowConversationManager({ windowSize: 20 })]
})Files to Modify
Source Files (8-10 files):
src/hooks/events.ts- Add retryModelCall fieldsrc/conversation-manager/null-conversation-manager.ts- Convert to HookProvidersrc/conversation-manager/sliding-window-conversation-manager.ts- Convert to HookProvidersrc/conversation-manager/conversation-manager.ts- DELETEsrc/conversation-manager/index.ts- Update exportssrc/agent/agent.ts- Remove direct calls, add retry logicsrc/index.ts- Update public exports
Test Files (~4 files):
src/conversation-manager/__tests__/null-conversation-manager.test.tssrc/conversation-manager/__tests__/sliding-window-conversation-manager.test.tssrc/conversation-manager/__tests__/conversation-manager.test.ts- DELETE or minimizesrc/agent/__tests__/agent.test.ts
Acceptance Criteria
- AfterModelCallEvent has retryModelCall field
- NullConversationManager implements HookProvider with 0 hooks
- SlidingWindowConversationManager implements HookProvider with proper callbacks
- Agent class has no conversationManager field or direct calls
- Agent properly handles retryModelCall flag for context overflow retry
- ConversationManager base class is removed
- Public API exports updated (breaking change)
- All tests pass with 80%+ coverage
- TSDoc comments updated for all modified public APIs
- Existing conversation management behavior preserved (just triggered differently)
Estimated Scope
- Complexity: Medium-High (breaking change, core agent loop modification)
- Files Modified: ~10-12 files
- Breaking Changes: Yes - removal of ConversationManager base class and AgentConfig.conversationManager field
- Estimated Effort: 2-3 days for implementation and testing
Notes
- This is intentionally different from Python implementation
- Breaking change requires version bump and migration documentation
- All existing conversation management behavior is preserved, just triggered via hooks instead of direct method calls
- The retry mechanism via retryModelCall provides more flexibility for custom hook implementations
Metadata
Metadata
Assignees
Labels
No labels