MCPcopy Create free account
hub / github.com/docker/docker-agent / FollowUpSession

Method FollowUpSession

pkg/server/session_manager.go:766–812  ·  view source on GitHub ↗

FollowUpSession enqueues user messages for end-of-turn processing in a running session. Each message is popped one at a time after the current turn finishes, giving each follow-up a full undivided agent turn. idempotencyKey, when non-empty, makes the call safe to retry: if a request with the same k

(ctx context.Context, sessionID string, messages []api.Message, idempotencyKey string)

Source from the content-addressed store, hash-verified

764// still enqueued but are not consumed until the next RunSession starts a
765// stream; the returned boolean indicates whether a stream is active.
766func (sm *SessionManager) FollowUpSession(ctx context.Context, sessionID string, messages []api.Message, idempotencyKey string) (streaming, duplicate bool, err error) {
767 rt, exists := sm.runtimeSessions.Load(sessionID)
768 if !exists {
769 return false, false, ErrSessionNotRunning
770 }
771
772 if idempotencyKey != "" {
773 cache, _ := sm.followUpKeys.LoadOrStore(sessionID, newIdempotencyCache(defaultIdempotencyCapacity))
774 if cache.reserve(idempotencyKey) {
775 return false, true, nil
776 }
777 // Roll the reservation back if we end up returning an error, so the
778 // caller can safely retry a failed request with the same key.
779 defer func() {
780 if err != nil {
781 cache.release(idempotencyKey)
782 }
783 }()
784 }
785
786 // Attached session: hand the follow-up to its owner (the TUI App) so a
787 // real turn starts and events reach all subscribers.
788 if inject, ok := sm.followUpInjectors.Load(sessionID); ok {
789 for _, msg := range messages {
790 inject(ctx, msg.Content)
791 }
792 return true, false, nil
793 }
794
795 for _, msg := range messages {
796 if err := rt.runtime.FollowUp(ctx, runtime.QueuedMessage{
797 Content: msg.Content,
798 MultiContent: msg.MultiContent,
799 }); err != nil {
800 return false, false, err
801 }
802 }
803
804 // Probe streaming state so the caller knows whether the follow-up
805 // will be consumed by the current turn or sit idle until the next.
806 streaming = !rt.streaming.TryLock()
807 if !streaming {
808 rt.streaming.Unlock()
809 }
810
811 return streaming, false, nil
812}
813
814// ResumeElicitation resumes an elicitation request.
815func (sm *SessionManager) ResumeElicitation(ctx context.Context, sessionID, action string, content map[string]any) error {

Callers

nothing calls this directly

Calls 7

newIdempotencyCacheFunction · 0.85
LoadMethod · 0.80
LoadOrStoreMethod · 0.80
reserveMethod · 0.80
FollowUpMethod · 0.65
releaseMethod · 0.45
UnlockMethod · 0.45

Tested by

no test coverage detected