Files
ai-agent/internal/ai/application/runtime/einoexperiment/react.go
T
mlogclub 34051a4631 feat: Enhance AI Agent and Channel Management
- Updated labels in the AI Agents dashboard for clarity, changing "流程状态" to "Playbook 状态" and "未发布流程" to "未发布 Playbook".
- Introduced AI Agent rollout percentage management in channel editing, allowing users to set and rollback rollout percentages.
- Added new API endpoints for rolling back AI Agent rollout and fetching agent run metrics.
- Implemented new UI components for displaying agent run details, including status, duration, and input/output tokens.
- Enhanced type definitions for AdminChannel and AIAgent to include rollout percentages and runtime modes.
- Updated navigation to include a section for agent runs.
- Added new translations for agent run features in both English and Chinese.
2026-07-25 12:04:06 +08:00

87 lines
3.0 KiB
Go

// Package einoexperiment contains an isolated Eino ReAct verification path.
// It must not be registered in the production Agent Engine registry.
package einoexperiment
import (
"context"
"fmt"
"strings"
"time"
"agent-desk/internal/models"
einoopenai "github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/flow/agent/react"
"github.com/cloudwego/eino/schema"
)
// ReActConfig keeps the experiment dependency-injected. The caller owns model
// construction, connection reuse, and all production configuration decisions.
type ReActConfig struct {
Model model.ToolCallingChatModel
Tools []tool.BaseTool
MaxSteps int
}
// NewOpenAICompatibleModel adapts an existing AgentDesk AI configuration to
// Eino's OpenAI-compatible chat model. It is intentionally not wired into any
// production Engine; the experiment owns the adoption decision.
func NewOpenAICompatibleModel(ctx context.Context, config models.AIConfig) (model.ToolCallingChatModel, error) {
if strings.TrimSpace(config.APIKey) == "" || strings.TrimSpace(config.BaseURL) == "" || strings.TrimSpace(config.ModelName) == "" {
return nil, fmt.Errorf("ai config base URL, API key, and model name are required")
}
modelConfig := &einoopenai.ChatModelConfig{
APIKey: strings.TrimSpace(config.APIKey),
BaseURL: strings.TrimSpace(config.BaseURL),
Model: strings.TrimSpace(config.ModelName),
}
if config.TimeoutMS > 0 {
modelConfig.Timeout = time.Duration(config.TimeoutMS) * time.Millisecond
}
if config.MaxOutputTokens > 0 {
maxTokens := config.MaxOutputTokens
modelConfig.MaxCompletionTokens = &maxTokens
}
return einoopenai.NewChatModel(ctx, modelConfig)
}
// NewReAct creates an Eino ReAct agent without registering it with AgentDesk's
// runtime. It is deliberately suitable only for technical verification.
func NewReAct(ctx context.Context, config ReActConfig) (*react.Agent, error) {
if config.Model == nil {
return nil, fmt.Errorf("eino experiment model is required")
}
maxSteps := config.MaxSteps
if maxSteps <= 0 {
maxSteps = 5
}
return react.NewAgent(ctx, &react.AgentConfig{
ToolCallingModel: config.Model,
ToolsConfig: compose.ToolsNodeConfig{Tools: config.Tools},
MaxStep: maxSteps,
})
}
// Run performs one non-streaming experiment. Context cancellation is passed
// directly to Eino and the injected model/tools.
func Run(ctx context.Context, config ReActConfig, input []*schema.Message) (*schema.Message, error) {
agent, err := NewReAct(ctx, config)
if err != nil {
return nil, err
}
return agent.Generate(ctx, input)
}
// Stream performs one streaming experiment. The caller must close the returned
// reader after consuming it.
func Stream(ctx context.Context, config ReActConfig, input []*schema.Message) (*schema.StreamReader[*schema.Message], error) {
agent, err := NewReAct(ctx, config)
if err != nil {
return nil, err
}
return agent.Stream(ctx, input)
}