package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"github.com/bytedance/sonic"
"github.com/google/uuid"
"github.com/hastekit/hastekit-sdk-go/pkg/agents"
"github.com/hastekit/hastekit-sdk-go/pkg/agents/agentstate"
"github.com/hastekit/hastekit-sdk-go/pkg/agents/history"
"github.com/hastekit/hastekit-sdk-go/pkg/gateway/llm/responses"
hastekit "github.com/hastekit/hastekit-sdk-go"
"github.com/hastekit/hastekit-sdk-go/pkg/utils"
)
// GetUserTool - runs immediately (no approval needed)
type GetUserTool struct {
*agents.BaseTool
}
func NewGetUserTool() *GetUserTool {
return &GetUserTool{
BaseTool: &agents.BaseTool{
RequiresApproval: false,
ToolUnion: responses.ToolUnion{
OfFunction: &responses.FunctionTool{
Name: "get_user",
Description: utils.Ptr("Gets user information"),
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"user_id": map[string]any{"type": "string"},
},
"required": []string{"user_id"},
},
},
},
},
}
}
func (t *GetUserTool) Execute(ctx context.Context, params *agents.ToolCall) (*agents.ToolCallResponse, error) {
return &agents.ToolCallResponse{
FunctionCallOutputMessage: &responses.FunctionCallOutputMessage{
ID: params.ID,
CallID: params.CallID,
Output: responses.FunctionCallOutputContentUnion{
OfString: utils.Ptr(`{"name": "John Doe", "email": "john@example.com"}`),
},
},
}, nil
}
// DeleteUserTool - requires approval
type DeleteUserTool struct {
*agents.BaseTool
}
func NewDeleteUserTool() *DeleteUserTool {
return &DeleteUserTool{
BaseTool: &agents.BaseTool{
RequiresApproval: true, // Human approval required
ToolUnion: responses.ToolUnion{
OfFunction: &responses.FunctionTool{
Name: "delete_user",
Description: utils.Ptr("Permanently deletes a user account"),
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"user_id": map[string]any{"type": "string"},
},
"required": []string{"user_id"},
},
},
},
},
}
}
func (t *DeleteUserTool) Execute(ctx context.Context, params *agents.ToolCall) (*agents.ToolCallResponse, error) {
args := map[string]any{}
json.Unmarshal([]byte(params.Arguments), &args)
return &agents.ToolCallResponse{
FunctionCallOutputMessage: &responses.FunctionCallOutputMessage{
ID: params.ID,
CallID: params.CallID,
Output: responses.FunctionCallOutputContentUnion{
OfString: utils.Ptr(fmt.Sprintf("User %s has been deleted", args["user_id"])),
},
},
}, nil
}
func main() {
ctx := context.Background()
client := hastekit.NewLLMClient([]hastekit.ProviderConfig{
{
ProviderName: hastekit.ProviderOpenAI,
ApiKeys: []*hastekit.APIKeyConfig{
{
Name: "Key 1",
APIKey: os.Getenv("OPENAI_API_KEY"),
},
},
},
})
agent := hastekit.NewAgent(&hastekit.AgentConfig{
Name: "User Manager",
Instruction: hastekit.NewPrompt("You help manage user accounts."),
LLM: client.Model("OpenAI/gpt-4o-mini"),
Tools: []hastekit.Tool{
NewGetUserTool(),
NewDeleteUserTool(),
},
History: hastekit.NewFileHistory("./conversations"),
})
// First execution - agent may request to delete a user
handle, err := agent.Execute(ctx, &agents.AgentInput{
Namespace: "default",
Message: history.Message{
Messages: []responses.InputMessageUnion{
responses.UserMessage("Delete user 123"),
},
},
})
if err != nil {
log.Fatal(err)
}
result, err := handle.Result()
if err != nil {
log.Fatal(err)
}
// Check if approval is needed
if result.Status == agentstate.RunStatusPaused {
fmt.Println("Approval required for:", result.Interrupts)
// Simulate user approval
approvalResponse := responses.InputMessageUnion{
OfFunctionCallInterruptResolution: &responses.FunctionCallInterruptResolutionMessage{
ID: uuid.NewString(),
Resolutions: []responses.InterruptResolution{
{
CallID: result.Interrupts[0].FunctionCallMessage.CallID,
Action: responses.InterruptActionApprove,
},
},
},
}
// Resume with approval
handle, err = agent.Execute(ctx, &agents.AgentInput{
Namespace: "default",
PreviousMessageID: result.RunID,
Message: history.Message{
Messages: []responses.InputMessageUnion{approvalResponse},
},
})
if err != nil {
log.Fatal(err)
}
result, err = handle.Result()
if err != nil {
log.Fatal(err)
}
}
buf, _ := sonic.Marshal(result.Output)
fmt.Println("Final result:", string(buf))
}