dispatch

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 10, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package dispatch is the runtime's production tool-dispatch concrete — the one full `steering.ToolExecutor` implementation (Phase 110a, D-194; originally Phase 83i, D-152, as the dev binary's executor).

Before 83i the runloop's default case dropped every planner CallTool decision on the floor (Phase 53's deliberately-punted scope), which made multi-step ReAct structurally broken against real LLMs because the planner never saw tool observations. The audit pinned this as the root cause of the "64 steps, 0 tools called" failure mode that surfaced in the v1.1 operator validation. Phase 110a promoted the executor out of `package main` (the SDK friction audit's Pattern 1 / P1 finding) so every assembly — `cmd/harbor`, `harbortest/devstack`, a headless embedder's own run loop — wires the SAME dispatch semantics via NewToolExecutor.

The executor closes the planner→runtime seam against the production `tools.ToolCatalog`:

  • CallTool: look up the descriptor by name, call Invoke under the per-step ctx, return the typed ToolResult.Value (plus Meta) as the observation. The planner's next step sees this on `RunContext.Trajectory.Steps[N].Observation`.

  • CallParallel: fan the branches out concurrently via `internal/runtime/parallel` in non-atomic mode (Phase 107d — D-169).

  • SpawnTask / AwaitTask: drive the background-task registry with spawn-depth caps and terminal-status polling (Phase 107e — D-170).

The executor is constructed once per stack and shared across every run; it holds only the catalog + artifact store + task registry (immutable after construction) + a logger, so the D-025 reuse contract is satisfied.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HeavyTruncationSummary

func HeavyTruncationSummary(tool string, raw any, encoded []byte, size int, artifactID string) any

HeavyTruncationSummary builds the small llmObservation the planner renders for a heavy tool result. For JSON-object results it emits a field-aware preview that preserves every top-level scalar / small field verbatim and replaces oversized nested values with a `[omitted: N bytes]` sentinel — so the model sees both what's available and what was pruned. For non-object results (arrays, scalars at top level) it falls back to byte-truncation at `previewTotalMaxBytes`.

Carries: the tool name, byte size of the full result, the preview, the `truncated: true` signal, and the artifact ID when available.

This exported identifier IS the heavy-truncation shape contract: the React planner's prompt renderer (`internal/planner/react/prompt.go::renderHeavyContentMap`) pattern-matches the `{tool, size_bytes, truncated, preview, artifact_ref}` map this function emits. Changing a key here is a prompt-renderer change in the same PR (Phase 110a re-pointed the renderer's citation from the pre-promotion `cmd/harbor` copy to this function).

func NewToolExecutor

func NewToolExecutor(cat tools.ToolCatalog, store artifacts.ArtifactStore, taskReg tasks.TaskRegistry, opts ...Option) steering.ToolExecutor

NewToolExecutor binds the catalog + artifact store + task registry the run loop dispatches against — the SAME instances the stack's boot wiring constructs. The returned executor covers all four non-Finish Decision shapes (CallTool, CallParallel, SpawnTask, AwaitTask) with the D-026 heavy-result→artifact promotion applied to every observation that reaches the planner / LLM edge.

`taskReg` MAY be nil in degraded wiring — SpawnTask / AwaitTask then fail loud with `steering.ErrDecisionShapeUnsupported` rather than panic. `store` MAY be nil — heavy results then degrade to a loudly logged truncated preview instead of an artifact promotion.

Concurrent reuse (D-025): the executor is a compiled artifact — construct once per stack, share across N concurrent runs. Per-run state lives in ctx + RunContext, never on the executor.

Types

type Option

type Option func(*toolExecutor)

Option configures the executor NewToolExecutor constructs.

func WithHeavyThreshold

func WithHeavyThreshold(bytes int) Option

WithHeavyThreshold sets the D-026 heavy-output threshold in bytes: tool results whose JSON encoding meets or exceeds it get promoted to artifact-backed truncation summaries before reaching the planner / LLM edge. Non-positive values fall back to the 32 KiB safety floor (the Wave 11 default) — the same normalization the pre-110a constructor applied, so passing an unset config value through is safe.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the executor's logger. Nil falls back to slog.Default().

func WithMaxSpawnDepth

func WithMaxSpawnDepth(n int) Option

WithMaxSpawnDepth caps the ParentTaskID-chain depth of planner-spawned background tasks (planner.absolute_max_spawn_depth). Non-positive values fall back to `config.DefaultSpawnDepthCap` (the one source of the spawn-depth default — D-196).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL