tool

package
v0.10.0-alpha.23 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package tool adapts explicitly capable external tools to durable background tasks.

Index

Examples

Constants

View Source
const (
	// ExecutorKey identifies non-recoverable managed tools.
	ExecutorKey = "eino.dev/background-tool"
	// RecoverableExecutorKey identifies managed tools that support Worker handoff.
	RecoverableExecutorKey = "eino.dev/recoverable-background-tool"
)

Variables

View Source
var (
	// ErrResumeInputRejected reports that resume data is invalid for the
	// current InputRequest. ResumableBackgroundTool.Resume must return this
	// error before applying side effects and with a nil Run. The framework
	// leaves the task waiting on the same request.
	ErrResumeInputRejected = errors.New(
		"backgroundtask/tool: resume input rejected",
	)
)

Functions

func NewManagedTool

func NewManagedTool(
	ctx context.Context,
	config *ManagedToolConfig,
) (componenttool.BaseTool, error)

NewManagedTool creates a wrapper implementing EnhancedInvokableTool and EnhancedStreamableTool. Every result includes a text control envelope; completed foreground results may append rich parts through Registration.RenderResult. Detaching closes only the caller projection; durable persistence continues.

Example
/*
 * Copyright 2026 CloudWeGo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/cloudwego/eino/adk/backgroundtask"
	backgroundtool "github.com/cloudwego/eino/adk/backgroundtask/tool"
	componenttool "github.com/cloudwego/eino/components/tool"
	"github.com/cloudwego/eino/schema"
)

type exampleTool struct{}

func (exampleTool) ValidateArguments(arguments string) error {
	var input map[string]any
	return json.Unmarshal([]byte(arguments), &input)
}
func (exampleTool) Start(
	context.Context,
	*backgroundtool.StartRequest,
) (*backgroundtool.StartResult, error) {
	return &backgroundtool.StartResult{Run: exampleRun{}}, nil
}

type exampleRun struct{}

func (exampleRun) Wait(context.Context) (*backgroundtool.Outcome, error) {
	return &backgroundtool.Outcome{
		Status: backgroundtask.StatusCompleted, Data: []byte("video ready"),
	}, nil
}
func (exampleRun) Stop(context.Context) error { return nil }

func main() {
	executors := backgroundtask.NewExecutorRegistry()
	manager, err := backgroundtask.New(context.Background(), &backgroundtask.Config{
		Executors: executors,
		SendTaskCreatedEvent: func(context.Context, *backgroundtask.Task) error {
			return nil
		},
		IDGen: func(context.Context, *backgroundtask.AllocateTaskIDRequest) (string, error) {
			return "task_video", nil
		},
	})
	if err != nil {
		panic(err)
	}
	registry := backgroundtool.NewRegistry()
	_ = registry.Register(&backgroundtool.Registration{
		Info: &schema.ToolInfo{
			Name: "generate_video", Desc: "Generate a product video",
			ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
				"prompt": {Type: schema.String, Required: true},
			}),
		},
		Tool: exampleTool{},
	})
	wrapped, _ := backgroundtool.NewManagedTool(context.Background(), &backgroundtool.ManagedToolConfig{
		Manager: manager, Executors: executors, Registry: registry, ToolName: "generate_video",
		SessionID: func(context.Context) (string, error) { return "session", nil },
	})
	result, _ := wrapped.(componenttool.EnhancedInvokableTool).InvokableRun(
		context.Background(), &schema.ToolArgument{Text: `{"prompt":"launch"}`},
	)
	var event backgroundtool.ManagedToolResponseEvent
	_ = json.Unmarshal([]byte(result.Parts[0].Text), &event)
	fmt.Println(event.TaskID, event.Status, event.Output)
}
Output:
completed video ready

func RegisterExecutors

func RegisterExecutors(executors *backgroundtask.ExecutorRegistry, registry *Registry) error

RegisterExecutors installs the plain and recoverable managed-tool executors.

func Submit

func Submit(
	ctx context.Context,
	manager *backgroundtask.Manager,
	registry *Registry,
	req *SubmitRequest,
) (*backgroundtask.Task, error)

Submit validates and persists one registered managed tool without invoking InputPreparer or exposing the private executor payload. Managed-tool executors for registry must already be registered with manager. If the returned error wraps backgroundtask.ErrTaskCreatedEventUndelivered and task is non-nil, durable ownership has transferred and callers must not retry Submit.

Types

type AdoptRequest

type AdoptRequest struct {
	TaskID         string
	Arguments      string
	Run            Run
	ToolCheckpoint []byte
}

AdoptRequest transfers an Attempt 0 foreground operation into background ownership. Run must be the live handle returned by the matching Start call.

type AdoptResult

type AdoptResult struct {
	Run            Run
	ToolCheckpoint []byte
}

AdoptResult contains the background-owned run handle and checkpoint to use for the first durable attempt after handoff.

type BackgroundTool

type BackgroundTool interface {
	ValidateArguments(arguments string) error
	Start(context.Context, *StartRequest) (*StartResult, error)
}

BackgroundTool starts one logical external operation. ValidateArguments must be repeatable and side-effect free. Start receives the Eino task ID before any external side effect occurs. Attempt 0 is a parent-owned foreground invocation with no persisted task or store-authorized attempt; background attempts start at 1 and must be preceded by Manager.Submit. InputPreparer supports ordinary Runner interruption before durable task creation. ResumableBackgroundTool supports durable input requests after creation. An error from Start is a durable execution failure for background attempts and a model-visible foreground failure for Attempt 0. For recoverable tools, Eino commits StartResult.Checkpoint and the external-start boundary before calling Run.Wait only for background attempts.

type ForegroundHandoffTool

type ForegroundHandoffTool interface {
	BackgroundTool
	Adopt(context.Context, *AdoptRequest) (*AdoptResult, error)
}

ForegroundHandoffTool can adopt a running Attempt 0 foreground operation into background ownership without repeating its side effects.

type InputPreparer

type InputPreparer interface {
	PrepareInput(
		ctx context.Context,
		arguments string,
	) (preparedArguments string, err error)
}

InputPreparer optionally completes or rewrites tool arguments before durable task creation. The managed-tool wrapper calls PrepareInput synchronously in the parent Runner tool invocation, before task ID allocation, output reservation, or persistence. Implementations may use components/tool StatefulInterrupt, GetInterruptState, and GetResumeContext normally.

PrepareInput may be re-entered by Runner and must not start the external operation or perform non-idempotent side effects. Its non-empty result must be the final JSON arguments: the framework validates, persists, and supplies them to policy callbacks and Start or Recover.

type InputRequest

type InputRequest struct {
	ID   string          `json:"id"`
	Data json.RawMessage `json:"data,omitempty"`
}

InputRequest describes the current durable question from a managed tool. ID must be stable for this question across recovery. Data must contain one valid JSON value and is embedded unchanged in model-facing responses.

func ReadInputRequest

func ReadInputRequest(task *backgroundtask.Task) (*InputRequest, error)

ReadInputRequest returns the application-facing request for a managed tool currently in StatusWaitingInput. The returned value owns its Data bytes.

type ManagedToolConfig

type ManagedToolConfig struct {
	// Manager and Executors are required; Executors must be the registry used by
	// Manager's workers.
	Manager   *backgroundtask.Manager
	Executors *backgroundtask.ExecutorRegistry
	// Registry and ToolName select a required registered implementation.
	Registry *Registry
	ToolName string

	// ForegroundTimeoutMs overrides the default foreground observation timeout.
	// Nil uses the framework default; non-positive disables the timer.
	ForegroundTimeoutMs *int
	// ShouldAutoBackground is evaluated after foreground timeout. Nil means
	// timeout the operation instead of detaching. It may be called concurrently.
	ShouldAutoBackground func(context.Context, *foreground.CandidateInfo) bool
	// RunInBackground requests explicit detachment from JSON arguments. Nil
	// never requests it and takes precedence over foreground timeout.
	RunInBackground func(context.Context, string) bool
	// InvocationTimeoutMs returns an optional operation timeout in milliseconds.
	// Nil or a nil result means no operation timeout.
	InvocationTimeoutMs func(context.Context, string) *int
	// SessionID resolves the optional session notification target. An empty
	// result disables session-routed lifecycle notifications. Nil uses the
	// current Runner session when one exists and otherwise disables notification.
	SessionID func(context.Context) (string, error)
}

ManagedToolConfig configures the framework-owned model-facing wrapper.

type ManagedToolResponseEvent

type ManagedToolResponseEvent struct {
	Type         ManagedToolResponseEventType `json:"type"`
	TaskID       string                       `json:"task_id,omitempty"`
	Status       backgroundtask.Status        `json:"status,omitempty"`
	Description  string                       `json:"description,omitempty"`
	Output       any                          `json:"output,omitempty"`
	Error        string                       `json:"error,omitempty"`
	InputRequest *InputRequest                `json:"input_request,omitempty"`
	Update       *Update                      `json:"update,omitempty"`
}

ManagedToolResponseEvent is the framework-owned model-facing text control envelope. The enhanced managed-tool wrapper encodes it as the first text part of every ToolResult; streaming uses one newline-terminated record per chunk. Type determines the legal variant: update events set only Update, while launch-result events set task identity, status, description, and either a waiting InputRequest or terminal Output or Error.

type ManagedToolResponseEventType

type ManagedToolResponseEventType string

ManagedToolResponseEventType identifies one model-facing managed-tool response variant.

const (
	// ManagedToolResponseEventUpdate carries one live progress Update. All other
	// ManagedToolResponseEvent fields are empty.
	ManagedToolResponseEventUpdate ManagedToolResponseEventType = "update"
	// ManagedToolResponseEventLaunchResult carries the task launch or foreground result.
	// Update is nil; the remaining fields describe the task and its current or
	// terminal outcome.
	ManagedToolResponseEventLaunchResult ManagedToolResponseEventType = "launch_result"
	// ManagedToolResponseEventForegroundResult carries a synchronous foreground
	// result. No TaskID is set because no background task was persisted.
	ManagedToolResponseEventForegroundResult ManagedToolResponseEventType = "foreground_result"
)

type MaterializeOutputRequest

type MaterializeOutputRequest struct {
	TaskID  string
	EventID string
	Path    string
	Data    []byte
}

MaterializeOutputRequest describes one caller-identified progress event.

type Outcome

type Outcome struct {
	Status       backgroundtask.Status
	Data         []byte
	Error        string
	InputRequest *InputRequest
	// Checkpoint replaces the latest opaque tool checkpoint when Status is
	// StatusWaitingInput and this field is non-empty. Empty retains the latest
	// checkpoint. Other statuses must leave it empty.
	Checkpoint []byte
}

Outcome is the authoritative logical-operation result. Completed outcomes may contain Data and no Error. Failed outcomes require Error and no Data. Canceled outcomes may contain Error and no Data. Waiting-input outcomes set InputRequest and may set Checkpoint; a non-empty Checkpoint replaces the latest tool checkpoint while an empty value retains it. Other statuses must leave InputRequest and Checkpoint empty. Waiting input is supported only by ResumableBackgroundTool.

type OutputMaterializer

type OutputMaterializer interface {
	// ReserveOutput must return the same path when repeated with one TaskID.
	// A reservation may remain unused when later task submission fails.
	ReserveOutput(context.Context, *ReserveOutputRequest) (string, error)
	AppendOutput(context.Context, *MaterializeOutputRequest) error
}

OutputMaterializer optionally projects caller-identified task events to a deterministic file or object. AppendOutput must durably deduplicate by (TaskID, EventID) for the task's recovery and retention lifetime. Distinct events must be applied in call order; EventID is opaque and must not be sorted. Recoverable update sources must therefore replay in stable order.

type ProgressReader

type ProgressReader struct {
	// contains filtered or unexported fields
}

ProgressReader formats a bounded recent view of managed-tool task events.

func NewProgressReader

func NewProgressReader(
	manager *backgroundtask.Manager,
	limit int,
) (*ProgressReader, error)

NewProgressReader creates a managed-tool progress reader. Limit is the number of newest events rendered; non-positive values use 20 and values above the store maximum are capped by ListTaskEvents.

func (*ProgressReader) ReadProgress

func (r *ProgressReader) ReadProgress(
	ctx context.Context,
	task *backgroundtask.Task,
) (string, error)

ReadProgress implements middleware executor-specific progress projection.

type RecoverRequest

type RecoverRequest struct {
	TaskID     string
	Arguments  string
	Attempt    int64
	Checkpoint []byte
}

RecoverRequest describes reconstruction of an existing logical operation. Checkpoint is an independently owned copy of the latest opaque tool checkpoint.

type RecoverableBackgroundTool

type RecoverableBackgroundTool interface {
	BackgroundTool
	Recover(context.Context, *RecoverRequest) (Run, error)
}

RecoverableBackgroundTool reconstructs the same logical operation after a Worker loss or graceful yield. Implementations must make Start idempotent by TaskID because Worker loss may occur after the external start but before Eino persists StartResult.Checkpoint and the started marker.

type Registration

type Registration struct {
	// Info and Tool are required and snapshotted by Register.
	Info *schema.ToolInfo
	Tool BackgroundTool
	// Description formats persisted arguments for task presentation. Nil uses
	// the tool name. It may be called concurrently, must not panic, and must
	// return the same value when repeated with the same arguments.
	Description func(arguments string) string
	// RenderResult returns rich content for a successfully completed foreground
	// result. The framework prepends its text control envelope to the returned
	// parts. Nil embeds raw result bytes in that envelope. It may be called
	// concurrently; errors are returned to the invoking model call without
	// changing terminal task state.
	RenderResult func(context.Context, *backgroundtask.Task) (*schema.ToolResult, error)
	// Materializer optionally derives an EventID-idempotent output file.
	Materializer OutputMaterializer
}

Registration binds a stable model-facing tool name to an implementation. Equivalent registrations must be installed on every Worker eligible to claim tasks for the selected executor key.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry stores plain and recoverable registrations independently so a name may migrate between capability classes while old persisted tasks remain valid.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty managed-tool registry.

func (*Registry) Register

func (r *Registry) Register(registration *Registration) error

Register adds a registration to the capability class implemented by Tool.

type ReserveOutputRequest

type ReserveOutputRequest struct {
	TaskID string
}

ReserveOutputRequest identifies the task whose derived output path is reserved.

type ResumableBackgroundTool

type ResumableBackgroundTool interface {
	RecoverableBackgroundTool
	// Resume validates and applies input atomically from the framework's
	// perspective. Invalid input returns ErrResumeInputRejected before any side
	// effect; other errors are durable execution failures.
	Resume(context.Context, *ResumeRequest) (Run, error)
}

ResumableBackgroundTool supports durable input requests after the operation has started. Resume must apply the same RequestID and Data idempotently: Worker loss may cause the framework to repeat the call on a later attempt.

Implementations keep operation state in their external durable backend. The framework persists opaque tool checkpoints and the current InputRequest but never interprets tool checkpoint bytes.

type ResumeRequest

type ResumeRequest struct {
	TaskID     string
	Arguments  string
	Attempt    int64
	RequestID  string
	Data       []byte
	Checkpoint []byte
}

ResumeRequest applies durable external input to a waiting logical operation. RequestID identifies the exact InputRequest being answered. Data is opaque to the framework and may be empty. Checkpoint is an independently owned copy of the checkpoint persisted at that waiting boundary. A later attempt may replay the same request.

type Run

type Run interface {
	Wait(context.Context) (*Outcome, error)
	Stop(context.Context) error
}

Run is an attempt-local handle for one logical external operation. Canceling Wait stops observation only. Stop requests logical cancellation and must be safe under repeated or concurrent calls.

type StartRequest

type StartRequest struct {
	TaskID    string
	Arguments string
	Attempt   int64
}

StartRequest describes an initial external-operation start.

type StartResult

type StartResult struct {
	Run        Run
	Checkpoint []byte
}

StartResult contains the attempt-local Run and the initial opaque tool checkpoint. For Attempt >= 1, Eino persists an independently owned copy before calling Run.Wait. For Attempt 0, the checkpoint is held in memory until foreground handoff or stored in the parent Runner checkpoint for foreground waiting-input. Checkpoint may be empty when TaskID alone is sufficient to recover and must be empty for a non-recoverable BackgroundTool.

type SubmitRequest

type SubmitRequest struct {
	TaskID      string
	ToolName    string
	Arguments   string
	Description string
	SessionID   string

	DisableLifecycleNotifications bool
}

SubmitRequest describes a registered managed tool submitted directly as a durable task. Empty TaskID asks Manager to allocate one. SessionID optionally identifies the session notification target. It may be empty only when DisableLifecycleNotifications is true.

type Update

type Update struct {
	EventID  string            `json:"event_id,omitempty"`
	Kind     string            `json:"kind,omitempty"`
	Data     []byte            `json:"data,omitempty"`
	Metadata map[string]string `json:"metadata,omitempty"`
}

Update is a bounded serializable progress event. Data is limited to 256 KiB, Kind to 128 bytes, and Metadata to 32 entries with keys and values at most 1024 bytes each. Recoverable implementations must assign a non-empty, lifetime-stable EventID and replay updates in logical order. For plain tools, the framework may generate an ID without mutating this value. EventID is not an ordering key or pagination cursor.

type UpdateSource

type UpdateSource interface {
	Updates() *schema.StreamReader[*Update]
}

UpdateSource optionally exposes replayable incremental updates. The framework calls Updates once per Run, owns and closes the returned reader, and expects it to close shortly after Wait reaches a terminal outcome. Recovery starts at the beginning of the replayable history; EventID deduplication removes repeats.

Directories

Path Synopsis
Package tooltest provides conformance checks for managed background tool implementations.
Package tooltest provides conformance checks for managed background tool implementations.

Jump to

Keyboard shortcuts

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