mirror of
https://github.com/langgenius/dify.git
synced 2026-08-15 04:59:46 +08:00
117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
// Package agentcli implements the dify-agent CLI that runs inside the sandbox
|
|
// container. It communicates with the Agent Stub server on the host via HTTP.
|
|
package agentcli
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/langgenius/dify/dify-agent-runtime/internal/envvar"
|
|
)
|
|
|
|
const (
|
|
EnvAPIBaseURL = envvar.EnvAgentStubAPIBaseURL
|
|
EnvAuthJWE = envvar.EnvAgentStubAuthJWE
|
|
EnvDriveBase = envvar.EnvAgentStubDriveBase
|
|
|
|
DefaultDriveBase = envvar.DefaultDriveBase
|
|
)
|
|
|
|
// Environment holds validated Agent Stub connection parameters.
|
|
type Environment struct {
|
|
URL string
|
|
AuthJWE string
|
|
}
|
|
|
|
// Endpoint represents a normalized HTTP Agent Stub endpoint.
|
|
type Endpoint struct {
|
|
URL string
|
|
}
|
|
|
|
var ErrMissingEnvironment = errors.New("missing required Agent Stub environment variables")
|
|
|
|
// ReadEnvironment reads and validates the Agent Stub env vars.
|
|
func ReadEnvironment() (*Environment, error) {
|
|
apiURL := strings.TrimSpace(os.Getenv(EnvAPIBaseURL))
|
|
authJWE := strings.TrimSpace(os.Getenv(EnvAuthJWE))
|
|
|
|
var missing []string
|
|
if apiURL == "" {
|
|
missing = append(missing, EnvAPIBaseURL)
|
|
}
|
|
if authJWE == "" {
|
|
missing = append(missing, EnvAuthJWE)
|
|
}
|
|
if len(missing) > 0 {
|
|
return nil, fmt.Errorf("%w: %s", ErrMissingEnvironment, strings.Join(missing, ", "))
|
|
}
|
|
|
|
endpoint, err := ParseEndpoint(apiURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid %s: %w", EnvAPIBaseURL, err)
|
|
}
|
|
|
|
return &Environment{
|
|
URL: endpoint.URL,
|
|
AuthJWE: authJWE,
|
|
}, nil
|
|
}
|
|
|
|
// HasEnvironment returns whether both required env vars are set.
|
|
func HasEnvironment() bool {
|
|
return os.Getenv(EnvAPIBaseURL) != "" && os.Getenv(EnvAuthJWE) != ""
|
|
}
|
|
|
|
// ReadDriveBase returns the configured drive base or the default.
|
|
func ReadDriveBase() string {
|
|
if v := strings.TrimSpace(os.Getenv(EnvDriveBase)); v != "" {
|
|
return v
|
|
}
|
|
return DefaultDriveBase
|
|
}
|
|
|
|
// ParseEndpoint parses an Agent Stub URL and normalizes it.
|
|
func ParseEndpoint(rawURL string) (*Endpoint, error) {
|
|
stripped := strings.TrimSpace(rawURL)
|
|
if stripped == "" {
|
|
return nil, errors.New("agent stub URL must not be empty")
|
|
}
|
|
|
|
parsed, err := url.Parse(stripped)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid URL: %w", err)
|
|
}
|
|
|
|
if parsed.Scheme != "http" && parsed.Scheme != "https" {
|
|
return nil, errors.New("agent stub URL must use http or https")
|
|
}
|
|
return parseHTTPEndpoint(parsed)
|
|
}
|
|
|
|
func parseHTTPEndpoint(parsed *url.URL) (*Endpoint, error) {
|
|
if parsed.Host == "" {
|
|
return nil, errors.New("agent stub URL must include a host")
|
|
}
|
|
if parsed.RawQuery != "" || parsed.Fragment != "" {
|
|
return nil, errors.New("agent stub URL must not include a query string or fragment")
|
|
}
|
|
if parsed.User != nil {
|
|
return nil, errors.New("agent stub URL must not include user info")
|
|
}
|
|
|
|
path := strings.TrimRight(parsed.Path, "/")
|
|
if path == "" || path == "/" {
|
|
path = "/agent-stub"
|
|
} else if path != "/agent-stub" {
|
|
return nil, errors.New("HTTP agent stub API base URL path must be empty or /agent-stub")
|
|
}
|
|
|
|
normalizedURL := fmt.Sprintf("%s://%s%s", parsed.Scheme, parsed.Host, path)
|
|
return &Endpoint{
|
|
URL: normalizedURL,
|
|
}, nil
|
|
}
|