/* * Copyright 2025 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 tool import ( "context" "fmt" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/schema" ) type ApprovalInfo struct { ToolName string ArgumentsInJSON string } type ApprovalResult struct { Approved bool DisapproveReason *string } func (ai *ApprovalInfo) String() string { return fmt.Sprintf("tool '%s' interrupted with arguments '%s', waiting for your approval, "+ "please answer with Y/N", ai.ToolName, ai.ArgumentsInJSON) } func init() { schema.Register[*ApprovalInfo]() } type InvokableApprovableTool struct { tool.InvokableTool } func (i InvokableApprovableTool) Info(ctx context.Context) (*schema.ToolInfo, error) { return i.InvokableTool.Info(ctx) } func (i InvokableApprovableTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...tool.Option, ) (string, error) { toolInfo, err := i.Info(ctx) if err != nil { return "", err } wasInterrupted, _, storedArguments := tool.GetInterruptState[string](ctx) if !wasInterrupted { return "", tool.StatefulInterrupt(ctx, &ApprovalInfo{ ToolName: toolInfo.Name, ArgumentsInJSON: argumentsInJSON, }, argumentsInJSON) } isResumeTarget, hasData, data := tool.GetResumeContext[*ApprovalResult](ctx) if isResumeTarget && hasData { if data.Approved { return i.InvokableTool.InvokableRun(ctx, storedArguments, opts...) } if data.DisapproveReason != nil { return fmt.Sprintf("tool '%s' disapproved, reason: %s", toolInfo.Name, *data.DisapproveReason), nil } return fmt.Sprintf("tool '%s' disapproved", toolInfo.Name), nil } isResumeTarget, _, _ = tool.GetResumeContext[any](ctx) if !isResumeTarget { return "", tool.StatefulInterrupt(ctx, &ApprovalInfo{ ToolName: toolInfo.Name, ArgumentsInJSON: storedArguments, }, storedArguments) } return i.InvokableTool.InvokableRun(ctx, storedArguments, opts...) }