Class DefaultWebAgentSessionManager
- All Implemented Interfaces:
WebAgentSessionManager,AutoCloseable
WebAgentSessionManager implementation that wires the in-memory and SPI components together to
realize design §7.1's submit flow on a single node, with cross-node hooks for distributed deployments.
The manager is intentionally stateless beyond the per-conversation collaborators: locks, inbox, signal bus, and
idempotency store are accessed exclusively through their SPIs. Local-only state — session cache, in-process event
publisher, signal subscriptions, and per-conversation idle-sweep scheduler — is owned and closed at
close().
Out of scope for close(): the AgentExecutionContext is agent-scoped and shared
across conversations; closing this manager closes cached sessions but does not close those
contexts (and must not — other agents/sessions may still hold references). Closing
AgentExecutionContext (and the McpClientManager / other ContextScoped resources it owns)
is the application bootstrap's responsibility, typically via OrcaAgentExecutionContextManager#destroyContext
at shutdown. See AgentSessionOpener and
docs/design/agent-execution-context-rescoping.md.
-
Constructor Summary
ConstructorsConstructorDescriptionDefaultWebAgentSessionManager(at.aimon.core.agent.session.AgentSessionFactory sessionFactory, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout) DefaultWebAgentSessionManager(at.aimon.core.agent.session.AgentSessionFactory sessionFactory, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout, SessionMetrics metrics) DefaultWebAgentSessionManager(AgentSessionOpener sessionOpener, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout) DefaultWebAgentSessionManager(AgentSessionOpener sessionOpener, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout, SessionMetrics metrics) -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Close the manager.booleancloseGracefully(Duration timeout) Stop accepting new submits and wait up totimeoutfor in-flight turns to finish, then close the manager.voiddeleteConversation(at.aimon.core.agent.conversation.ConversationId conversationId) Permanently delete the conversation, including the history persisted inConversationRepository.Flow.Publisher<at.aimon.core.agent.stream.AgentExecutionEvent> events(at.aimon.core.agent.conversation.ConversationId conversationId) Subscribe to streaming progress events forconversationId.voidinterrupt(at.aimon.core.agent.conversation.ConversationId conversationId, at.aimon.core.agent.interrupt.InterruptReason reason) Trip an interrupt on the active turn, if any.voidreleaseConversation(at.aimon.core.agent.conversation.ConversationId conversationId) Release the local session cache entry and emitonComplete()on the correspondingevents()publisher.submit(WebSubmitRequest request) Submit one turn of input to the conversation identified byrequest.
-
Constructor Details
-
DefaultWebAgentSessionManager
public DefaultWebAgentSessionManager(at.aimon.core.agent.session.AgentSessionFactory sessionFactory, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout) -
DefaultWebAgentSessionManager
public DefaultWebAgentSessionManager(at.aimon.core.agent.session.AgentSessionFactory sessionFactory, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout, SessionMetrics metrics) -
DefaultWebAgentSessionManager
public DefaultWebAgentSessionManager(AgentSessionOpener sessionOpener, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout) -
DefaultWebAgentSessionManager
public DefaultWebAgentSessionManager(AgentSessionOpener sessionOpener, at.aimon.core.agent.conversation.ConversationRepository repository, ConversationLock lock, ConversationSignalBus signalBus, ConversationInbox inbox, IdempotencyStore idempotencyStore, String nodeId, Duration idleTtl, int maxCachedSessions, Duration lockLease, Duration lockExtendInterval, Duration holderLossSweepInterval, Duration idempotencyPrimaryTtl, Duration idempotencySecondaryTtl, Duration releaseInterruptTimeout, SessionMetrics metrics)
-
-
Method Details
-
submit
Description copied from interface:WebAgentSessionManagerSubmit one turn of input to the conversation identified byrequest.The manager evaluates
WebSubmitRequest.getAgentRef()against the conversation's current binding (design §3.6) and either runs the turn locally (lock acquired) or delivers the input to the cross-node inbox (lock held elsewhere).- Specified by:
submitin interfaceWebAgentSessionManager- Parameters:
request- the submit request (must not be null)- Returns:
- outcome describing whether the turn ran here or was queued for another node
-
events
public Flow.Publisher<at.aimon.core.agent.stream.AgentExecutionEvent> events(at.aimon.core.agent.conversation.ConversationId conversationId) Description copied from interface:WebAgentSessionManagerSubscribe to streaming progress events forconversationId.The publisher fan-outs both locally-emitted events (when this node owns the turn) and remote events arriving via the signal bus (when another node owns the turn). Multi-subscriber: several SSE clients may observe the same conversation simultaneously. Subscribers receive
onComplete()onWebAgentSessionManager.releaseConversation(ConversationId).- Specified by:
eventsin interfaceWebAgentSessionManager- Parameters:
conversationId- the conversation (must not be null)- Returns:
- a
Flow.Publisherof events
-
interrupt
public void interrupt(at.aimon.core.agent.conversation.ConversationId conversationId, at.aimon.core.agent.interrupt.InterruptReason reason) Description copied from interface:WebAgentSessionManagerTrip an interrupt on the active turn, if any.The manager broadcasts an
INTERRUPTsignal — every node trips its own active session for that conversation. Idempotent: when no turn is active anywhere, the call is a silent no-op.- Specified by:
interruptin interfaceWebAgentSessionManager- Parameters:
conversationId- the conversation (must not be null)reason- the interrupt classification (must not be null)
-
releaseConversation
public void releaseConversation(at.aimon.core.agent.conversation.ConversationId conversationId) Description copied from interface:WebAgentSessionManagerRelease the local session cache entry and emitonComplete()on the correspondingevents()publisher.History stored in
ConversationRepositoryis preserved — submitting again with the same id resumes the conversation. For permanent deletion (history removal) callWebAgentSessionManager.deleteConversation(ConversationId)instead; directrepository.delete(id)bypasses the manager's lock and races in-flight turns (design §13 issue #10).- Specified by:
releaseConversationin interfaceWebAgentSessionManager- Parameters:
conversationId- the conversation (must not be null)
-
deleteConversation
public void deleteConversation(at.aimon.core.agent.conversation.ConversationId conversationId) Description copied from interface:WebAgentSessionManagerPermanently delete the conversation, including the history persisted inConversationRepository.Implementations MUST acquire the conversation lock first (broadcasting
INTERRUPT(SESSION_RELEASED)on contention so the current holder yields) and only then callrepository.delete(id). This closes design §13 issue #10: a directrepository.delete(id)from outside the manager would race the in-flight turn (the holder may still be writing history) and corrupt cluster state.After delete the manager performs the same teardown as
WebAgentSessionManager.releaseConversation(ConversationId)(cache eviction, inbox purge, terminalInterruptedAt,onComplete,EVICTbroadcast).The default implementation throws
UnsupportedOperationExceptionso existing in-process tests and minimal implementations remain source-compatible.- Specified by:
deleteConversationin interfaceWebAgentSessionManager- Parameters:
conversationId- the conversation (must not be null)
-
close
public void close()Description copied from interface:WebAgentSessionManagerClose the manager. Local sessions are closed; application-scoped collaborators (factory, executor, repository, scheduling components) are not.- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceWebAgentSessionManager
-
closeGracefully
Description copied from interface:WebAgentSessionManagerStop accepting new submits and wait up totimeoutfor in-flight turns to finish, then close the manager. SubsequentWebAgentSessionManager.submit(WebSubmitRequest)calls during draining throwIllegalStateException.If the timeout elapses before all turns drain, surviving turns are interrupted with
InterruptReason.SYSTEM_SHUTDOWNand the manager proceeds to a hard close. The lock release on each surviving turn flips the lease so other nodes can take over.- Specified by:
closeGracefullyin interfaceWebAgentSessionManager- Parameters:
timeout- maximum time to wait for in-flight turns;Duration.ZEROdisables draining and matchesWebAgentSessionManager.close()semantics (must not be null, must not be negative)- Returns:
trueif all in-flight turns drained cleanly withintimeout,falseon timeout
-