mirror of
https://github.com/docker/docker-agent.git
synced 2026-11-04 10:02:15 +00:00
HTTP/SSE transport, reconnect recovery, and remote OAuth should not be dependencies of local execution. Move their implementations and tests into runtime/remote and migrate remote callers directly, without compatibility re-exports. Keep the existing Runtime interface, Event types, constructors, and event sinks in runtime. The dependency is intentionally one-way: remote imports runtime, while local execution never imports remote. A regression test enforces this boundary; extracting shared types can be considered separately.
73 lines
3.9 KiB
Go
73 lines
3.9 KiB
Go
package runtime
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/docker/docker-agent/pkg/tools"
|
|
)
|
|
|
|
// defaultEventChannelCapacity is the buffer size used for every Event
|
|
// channel the runtime hands back to a caller. Sized large enough that a
|
|
// reasonable producer (the run loop, a stream forwarder) can stay ahead of
|
|
// a typical consumer (the TUI, an API server) without blocking, but small
|
|
// enough to keep memory pressure bounded when consumers are slow.
|
|
//
|
|
// All event-channel constructors in pkg/runtime go through this constant
|
|
// so the buffer size is set in exactly one place.
|
|
const defaultEventChannelCapacity = 128
|
|
|
|
// defaultMaxOverflowCompactions caps the number of consecutive
|
|
// context-overflow auto-compactions that the run loop will attempt before
|
|
// giving up and surfacing the error to the caller. The runtime's
|
|
// compaction routine cannot guarantee that the resulting transcript will
|
|
// fit inside the model's context window (very large recent messages may
|
|
// still exceed it), so this bound prevents an infinite retry loop.
|
|
//
|
|
// Production uses 1 (one compaction attempt per stream); tests can change
|
|
// this via WithMaxOverflowCompactions to verify both the "compaction
|
|
// succeeded" and "compaction exhausted" branches without having to drive
|
|
// many real overflows.
|
|
const defaultMaxOverflowCompactions = 1
|
|
|
|
// toolsChangedTimeout bounds how long a single MCP-tool-change refresh
|
|
// may take. The handler is invoked outside any RunStream goroutine (it's
|
|
// a notification from a server), so a slow or stuck server cannot be
|
|
// allowed to wedge the caller indefinitely.
|
|
const toolsChangedTimeout = 5 * time.Second
|
|
|
|
// defaultStreamStoppedDeliveryTimeout bounds how long finalizeEventChannel
|
|
// waits to deliver StreamStopped when the event buffer is full. 128 buffered
|
|
// events at roughly a millisecond each for a synchronous per-delta SQLite
|
|
// write (the common back-pressure source, see #4136) drain in ~130ms; 5s is
|
|
// comfortably above that for any consumer still reading, while still bounding
|
|
// teardown once a consumer has abandoned the channel (the #3070 deadlock this
|
|
// replaces). Tests shrink it via the streamStoppedDeliveryTimeout field.
|
|
const defaultStreamStoppedDeliveryTimeout = 5 * time.Second
|
|
|
|
// defaultToolListTimeout bounds how long EmitStartupInfo waits for a single
|
|
// toolset to enumerate its tools while populating the sidebar. A toolset
|
|
// whose Tools() blocks indefinitely — e.g. an MCP stdio subprocess that
|
|
// never answers tools/list, possibly while also ignoring context
|
|
// cancellation — would otherwise stall the whole startup: the terminal
|
|
// ToolsetInfo{Loading:false} event is never emitted, so the sidebar stays
|
|
// on "Loading tools…" forever and /quit appears to hang. A timed-out
|
|
// toolset is skipped here; it stays usable for the actual agent turn, which
|
|
// lists its tools again without this startup bound. Tests override it via
|
|
// WithToolListTimeout to exercise the skip path without a real-time wait.
|
|
const defaultToolListTimeout = 10 * time.Second
|
|
|
|
// defaultToolStartTimeout bounds how long EmitStartupInfo waits for a single
|
|
// toolset to start while populating the sidebar. A toolset whose Start()
|
|
// blocks indefinitely — e.g. an MCP stdio server backed by a wedged Docker
|
|
// daemon that never finishes launching the container — would otherwise stall
|
|
// the loop the same way a hung Tools() does: the terminal
|
|
// ToolsetInfo{Loading:false} event is never emitted and the sidebar animates
|
|
// "tools available…" forever. A timed-out toolset is skipped for this startup
|
|
// pass only — the original start attempt keeps running and the toolset is
|
|
// picked up once it completes. It aliases the shared bounded-start default so
|
|
// this startup probe and the agent's turn path give up on a wedged toolset
|
|
// after the same grace period; it is longer than defaultToolListTimeout
|
|
// because a cold start can legitimately include an image pull. Tests override
|
|
// it via WithToolStartTimeout.
|
|
const defaultToolStartTimeout = tools.DefaultStartTimeout
|