MCPcopy Index your code
hub / github.com/docker/docker-agent / runTurn

Method runTurn

pkg/runtime/loop.go:627–958  ·  view source on GitHub ↗

runTurn performs one iteration of the run-stream loop, from turn_start onwards. Wrapping the body in its own function exists for one reason: a deferred call can fire turn_end on every exit path — a normal stop, an error from handleStreamError, a hook-driven shutdown, the loop detector, context cance

(
	ctx context.Context,
	sess *session.Session,
	a *agent.Agent,
	m *modelsdev.Model,
	model provider.Provider,
	modelID modelsdev.ID,
	contextLimit int64,
	sessionSpan trace.Span,
	agentTools []tools.Tool,
	ls *loopState,
	events EventSink,
)

Source from the content-addressed store, hash-verified

625// (overflowCompactions, toolModelOverride) is mutated through the
626// shared loopState pointer.
627func (r *LocalRuntime) runTurn(
628 ctx context.Context,
629 sess *session.Session,
630 a *agent.Agent,
631 m *modelsdev.Model,
632 model provider.Provider,
633 modelID modelsdev.ID,
634 contextLimit int64,
635 sessionSpan trace.Span,
636 agentTools []tools.Tool,
637 ls *loopState,
638 events EventSink,
639) turnControl {
640 streamAttrs := []attribute.KeyValue{
641 attribute.String(genai.AttrConversationID, sess.ID),
642 attribute.String(genai.AttrAgentNameRuntime, a.Name()),
643 }
644 if genai.EmitLegacyAttributes() {
645 streamAttrs = append(streamAttrs,
646 attribute.String("agent", a.Name()),
647 attribute.String("session.id", sess.ID),
648 )
649 }
650 streamCtx, streamSpan := r.startSpan(ctx, "runtime.stream", trace.WithAttributes(streamAttrs...))
651 // streamSpan ends inline at the natural points (success path before
652 // recordAssistantMessage, error path after handleStreamError) so its
653 // duration tracks the model call only, not the whole iteration. The
654 // boolean prevents a double-End on paths that already closed it.
655 spanEnded := false
656 endStreamSpan := func() {
657 if !spanEnded {
658 streamSpan.End()
659 spanEnded = true
660 }
661 }
662 defer endStreamSpan()
663
664 // endReason is set by every exit branch below and read by the
665 // deferred turn_end dispatch. Default = normal so a clean fall-
666 // through (model produced output, more tool calls, no hook
667 // blocked) reports "continue" or "normal" depending on which
668 // branch ran last. Branches overwrite this before returning.
669 endReason := turnEndReasonNormal
670 defer func() {
671 if ctxErr := ctx.Err(); ctxErr != nil && endReason == turnEndReasonNormal {
672 // Context cancellation is detected after the fact: a
673 // branch that returned early because of ctx.Err overrides
674 // the default, but a panic-recovered branch may not have
675 // had the chance, so re-check here.
676 endReason = turnEndReasonCanceled
677 }
678 // Use a non-cancellable context so turn_end runs even when
679 // the stream was interrupted (Ctrl+C, parent cancellation),
680 // matching the same guarantee session_end has at the
681 // finalizeEventChannel level.
682 r.executeTurnEndHooks(context.WithoutCancel(ctx), sess, a, endReason, events)
683 ls.exitReason = endReason
684 }()

Callers 1

runStreamLoopMethod · 0.95

Calls 15

startSpanMethod · 0.95
executeTurnEndHooksMethod · 0.95
executeTurnStartHooksMethod · 0.95
handleStreamErrorMethod · 0.95
processToolCallsMethod · 0.95
reprobeMethod · 0.95
notifyErrorMethod · 0.95

Tested by

no test coverage detected