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

Method emitToolsProgressively

pkg/runtime/runtime.go:1560–1671  ·  view source on GitHub ↗

emitToolsProgressively loads tools from each toolset and emits progress updates. This allows the UI to show the tool count incrementally as each toolset loads, with a spinner indicating that more tools may be coming.

(ctx context.Context, a *agent.Agent, send func(Event) bool)

Source from the content-addressed store, hash-verified

1558// This allows the UI to show the tool count incrementally as each toolset loads,
1559// with a spinner indicating that more tools may be coming.
1560func (r *LocalRuntime) emitToolsProgressively(ctx context.Context, a *agent.Agent, send func(Event) bool) {
1561 toolsets := a.ToolSets()
1562 totalToolsets := len(toolsets)
1563
1564 // If no toolsets, emit final state immediately
1565 if totalToolsets == 0 {
1566 send(ToolsetInfo(0, false, r.currentAgentName()))
1567 return
1568 }
1569
1570 // Emit initial loading state
1571 if !send(ToolsetInfo(0, true, r.currentAgentName())) {
1572 return
1573 }
1574
1575 // Load tools from each toolset and emit progress
1576 var totalTools int
1577 for i, toolset := range toolsets {
1578 // Check context before potentially slow operations
1579 if ctx.Err() != nil {
1580 return
1581 }
1582
1583 isLast := i == totalToolsets-1
1584
1585 // Start the toolset if needed, including recovery: a previously-started
1586 // toolset whose inner connection died (e.g. background invalid_token)
1587 // must have its recovery Start() called here so ShouldReportRecoveryFailure
1588 // can fire the targeted re-auth notice. Start() is a no-op when the
1589 // toolset is already healthy, so calling it unconditionally is safe.
1590 if startable, ok := toolset.(*tools.StartableToolSet); ok {
1591 if err := startToolsetWithTimeout(ctx, startable, r.toolStartTimeout); err != nil {
1592 desc := tools.DescribeToolSet(startable.ToolSet)
1593 // A start that outlived its deadline (e.g. an MCP container
1594 // stuck behind a wedged Docker daemon) is reported directly:
1595 // the abandoned Start goroutine has not returned, so the
1596 // once-per-streak guard below has recorded nothing and would
1597 // silently swallow the warning.
1598 if errors.Is(err, context.DeadlineExceeded) && ctx.Err() == nil {
1599 slog.WarnContext(ctx, "Toolset start timed out; skipping",
1600 "agent", a.Name(), "toolset", desc, "timeout", r.toolStartTimeout)
1601 a.AddToolWarning(fmt.Sprintf("%s is taking too long to start (>%s) — it keeps starting in the background and its tools appear once it is ready", desc, r.toolStartTimeout))
1602 continue
1603 }
1604 // IsAuthorizationRequired must be checked BEFORE
1605 // ShouldReportFailure: this is the first — expected —
1606 // failure of a deferred-OAuth toolset, and consuming the
1607 // failure-reported flag here would suppress the *real*
1608 // failure (e.g. server 4xx on the eventual interactive
1609 // retry) that the user actually needs to see.
1610 if mcptools.IsAuthorizationRequired(err) {
1611 // Two cases:
1612 // 1. Initial startup deferral (toolset never ran): the
1613 // OAuth dialog will appear naturally on the first user
1614 // message — no need to pre-announce it.
1615 // 2. Recovery: the toolset was previously working but the
1616 // background watcher detected a server-side invalid_token
1617 // (fixes #3198). Surface a deduped re-auth notice so the

Calls 11

currentAgentNameMethod · 0.95
DescribeToolSetFunction · 0.92
ToolsetInfoFunction · 0.85
startToolsetWithTimeoutFunction · 0.85
listToolsWithTimeoutFunction · 0.85
ToolSetsMethod · 0.80
AddToolWarningMethod · 0.80
ShouldReportFailureMethod · 0.80
ErrMethod · 0.65
NameMethod · 0.65