config

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package config

Example: Using Security Configuration

## Overview

The security configuration feature allows you to separate sensitive data (API keys, tokens, secrets, passwords) from your main configuration. The system automatically loads values from `.security.yml` and applies them to the corresponding fields in your config.

**Key Points:** - Values from `.security.yml` are automatically mapped to config fields - No `ref:` syntax is needed - just omit sensitive fields from config.json - If a field exists in both files, `.security.yml` value takes precedence - You can mix direct values in config.json with security values

## 1. Create .security.yml

File: ~/.facet-studio/.security.yml

```yaml # Model API Keys # All models MUST use 'api_keys' (plural) array format # Even a single key must be provided as an array with one element model_list:

gpt-5.4:
  api_keys:
    - "sk-proj-your-actual-openai-key-1"
    - "sk-proj-your-actual-openai-key-2"  # Optional: Multiple keys for failover
claude-sonnet-4.6:
  api_keys:
    - "sk-ant-your-actual-anthropic-key"  # Single key in array format

# Channel Tokens channels:

telegram:
  token: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
discord:
  token: "your-discord-bot-token"

# Web Tool Keys # Brave, Tavily, Perplexity, Kagi: Use 'api_keys' array # GLMSearch, BaiduSearch: Use 'api_key' single string web:

brave:
  api_keys:
    - "BSAyour-brave-api-key-1"
    - "BSAyour-brave-api-key-2"  # Optional: Multiple keys for failover
tavily:
  api_keys:
    - "tvly-your-tavily-api-key"  # Single key in array format
perplexity:
  api_keys:
    - "pplx-your-perplexity-api-key"  # Single key in array format
kagi:
  api_keys:
    - "your-kagi-api-key"  # Single key in array format
glm_search:
  api_key: "your-glm-search-api-key"  # Single key (not array)
baidu_search:
  api_key: "your-baidu-search-api-key"  # Single key (not array)

```

## 2. Simplify config.json

File: ~/.facet-studio/config.json

Note: Sensitive fields are omitted because they're loaded from .security.yml

```json

{
  "version": 1,
  "agents": {
    "defaults": {
      "workspace": "~/facet-studio-workspace",
      "model_name": "gpt-5.4"
    }
  },
  "model_list": [
    {
      "model_name": "gpt-5.4",
      "model": "openai/gpt-5.4",
      "api_base": "https://api.openai.com/v1"
      // api_key is automatically loaded from .security.yml
    },
    {
      "model_name": "claude-sonnet-4.6",
      "model": "anthropic/claude-sonnet-4.6",
      "api_base": "https://api.anthropic.com/v1"
      // api_key is automatically loaded from .security.yml
    }
  ],
  "channels": {
    "telegram": {
      "enabled": true
      // token is automatically loaded from .security.yml
    },
    "discord": {
      "enabled": true
      // token is automatically loaded from .security.yml
    }
  },
  "tools": {
    "web": {
      "brave": {
        "enabled": true
        // api_key is automatically loaded from .security.yml
      },
      "tavily": {
        "enabled": true
        // api_key is automatically loaded from .security.yml
      },
      "glm_search": {
        "enabled": true
        // api_key is automatically loaded from .security.yml
      },
      "baidu_search": {
        "enabled": true
        // api_key is automatically loaded from .security.yml
      }
    }
  }
}

```

## 3. Set proper permissions

```bash chmod 600 ~/.facet-studio/.security.yml ```

## 4. Add to .gitignore

```gitignore # Security configuration .security.yml ```

## 5. Verify it works

```bash facet-studio --version ```

Supported Fields in .security.yml

## Model API Keys

All models MUST use the `api_keys` (plural) array format in .security.yml.

```yaml model_list:

<model_name>:
  api_keys:
    - "key-1"
    - "key-2"  # Optional: Multiple keys for failover

```

Examples: ```yaml model_list:

gpt-5.4:
  api_keys:
    - "sk-proj-key-1"
    - "sk-proj-key-2"
claude-sonnet-4.6:
  api_keys:
    - "sk-ant-key"

```

**Important:** - Always use `api_keys` (plural) for models - Even a single key must be in an array format - The model_name in .security.yml must match the model_name in config.json

## Channel Tokens/Secrets

```yaml channels:

telegram:
  token: "value"
feishu:
  app_secret: "value"
  encrypt_key: "value"
  verification_token: "value"
discord:
  token: "value"
weixin:
  token: "value"
qq:
  app_secret: "value"
dingtalk:
  client_secret: "value"
slack:
  bot_token: "value"
  app_token: "value"
matrix:
  access_token: "value"
line:
  channel_secret: "value"
  channel_access_token: "value"
onebot:
  access_token: "value"
wecom:
  token: "value"
  encoding_aes_key: "value"
wecom_app:
  corp_secret: "value"
  token: "value"
  encoding_aes_key: "value"
wecom_aibot:
  secret: "value"
  token: "value"
  encoding_aes_key: "value"
pico:
  token: "value"
irc:
  password: "value"
  nickserv_password: "value"
  sasl_password: "value"

## Web Tool API Keys

**Brave, Tavily, Perplexity, Kagi:** ```yaml web:

brave:
  api_keys:
    - "BSA-key-1"
    - "BSA-key-2"
tavily:
  api_keys:
    - "tvly-key"
perplexity:
  api_keys:
    - "pplx-key"
kagi:
  api_keys:
    - "kagi-key"

``` Use `api_keys` (plural) array format.

**GLMSearch, BaiduSearch:** ```yaml web:

glm_search:
  api_key: "your-glm-key"
baidu_search:
  api_key: "your-baidu-key"

``` Use `api_key` (singular) single string format.

## Skills Registry Tokens

```yaml skills:

github:
  token: "value"
clawhub:
  auth_token: "value"

```

Backward Compatibility

You can still use direct values in config.json if needed:

```json

{
  "model_list": [
    {
      "model_name": "local-model",
      "model": "ollama/llama3",
      "api_base": "http://localhost:11434/v1",
      "api_key": "ollama"  // Direct value (works fine)
    }
  ]
}

```

You can also mix security values and direct values:

```json

{
  "model_list": [
    {
      "model_name": "cloud-model",
      // api_key loaded from .security.yml
    },
    {
      "model_name": "local-model",
      "model": "ollama/llama3",
      "api_base": "http://localhost:11434/v1",
      "api_key": "ollama"  // Direct value
    }
  ]
}

```

**Priority Order:** 1. Environment variables (highest priority) 2. .security.yml values 3. config.json direct values (lowest priority)

Migration from Old Config

## Step 1: Backup your config ```bash cp ~/.facet-studio/config.json ~/.facet-studio/config.json.backup ```

## Step 2: Create .security.yml ```bash cp security.example.yml ~/.facet-studio/.security.yml ```

## Step 3: Fill in your API keys Edit ~/.facet-studio/.security.yml and replace placeholders with your actual keys.

## Step 4: Simplify config.json (Recommended) Remove sensitive fields from ~/.facet-studio/config.json: - `api_key` fields from model_list entries - `token` fields from channels - `api_key` fields from tools.web - `token`/`auth_token` fields from tools.skills

## Step 5: Set permissions ```bash chmod 600 ~/.facet-studio/.security.yml ```

## Step 6: Test ```bash facet-studio --version ```

If everything works, you can delete the backup: ```bash rm ~/.facet-studio/config.json.backup ```

Advanced Features

## Multiple API Keys (Load Balancing & Failover)

You can configure multiple API keys for models and web tools to enable: - **Load balancing**: Requests are distributed across multiple keys - **Failover**: If a key fails, the system automatically switches to another key - **Rate limit management**: Distribute usage across multiple keys - **High availability**: Reduce downtime during API provider issues

### Example: Model with Multiple Keys

**.security.yml:** ```yaml model_list:

gpt-5.4:
  api_keys:
    - "sk-proj-key-1"
    - "sk-proj-key-2"
    - "sk-proj-key-3"

```

**config.json:** ```json

{
  "model_list": [
    {
      "model_name": "gpt-5.4",
      "model": "openai/gpt-5.4",
      "api_base": "https://api.openai.com/v1"
    }
  ]
}

```

### Example: Web Tool with Multiple Keys

**.security.yml:** ```yaml web:

brave:
  api_keys:
    - "BSA-key-1"
    - "BSA-key-2"
tavily:
  api_keys:
    - "tvly-your-key"  # Single key in array format
glm_search:
  api_key: "your-glm-key"  # GLMSearch uses single key format

```

**config.json:** ```json

{
  "tools": {
    "web": {
      "brave": {
        "enabled": true
      },
      "tavily": {
        "enabled": true
      },
      "glm_search": {
        "enabled": true
      }
    }
  }
}

```

## Single Key Format

**Models, Brave, Tavily, Perplexity, Kagi:** ```yaml model_list:

gpt-5.4:
  api_keys:
    - "sk-proj-your-key"  # Single key in array format

```

**GLMSearch, BaiduSearch:** ```yaml web:

glm_search:
  api_key: "your-glm-key"  # Single key (not array)

```

## Model Name Matching

The system supports intelligent model name matching in .security.yml:

### Example 1: Exact Match

**config.json:** ```json

{
  "model_name": "gpt-5.4:0"
}

```

**.security.yml (exact match with index):** ```yaml model_list:

gpt-5.4:0:
  api_keys: ["key-1"]

```

### Example 2: Base Name Match

**config.json:** ```json

{
  "model_name": "gpt-5.4:0"
}

```

**.security.yml (base name without index):** ```yaml model_list:

gpt-5.4:
  api_keys: ["key-1", "key-2"]

```

Both methods work. The base name match allows you to use simpler keys in .security.yml even when your config uses indexed model names for load balancing.

## Security File Permissions

The security file should have restricted permissions:

```bash chmod 600 ~/.facet-studio/.security.yml ```

This ensures only the owner can read and write the file.

Security Best Practices

1. Never commit .security.yml to version control 2. Add .security.yml to your .gitignore file 3. Set file permissions: chmod 600 ~/.facet-studio/.security.yml 4. Use different keys for different environments (dev, staging, production) 5. Rotate keys regularly and update .security.yml 6. Encrypt backups containing .security.yml 7. Review access regularly

Environment Variables

You can override any security value using environment variables:

```bash # Channels export FACET_STUDIO_CHANNELS_TELEGRAM_TOKEN="token-from-env" export FACET_STUDIO_CHANNELS_DISCORD_TOKEN="discord-token-from-env"

# Web Tools export FACET_STUDIO_TOOLS_WEB_BRAVE_API_KEY="brave-key-from-env" export FACET_STUDIO_TOOLS_WEB_BAIDU_API_KEY="baidu-key-from-env"

# Skills export FACET_STUDIO_TOOLS_SKILLS_GITHUB_TOKEN="github-token-from-env" ```

Environment variables have the highest priority and will override both config.json and .security.yml values.

Troubleshooting

## Error: "failed to load security config" - Ensure .security.yml exists in the same directory as config.json - Check YAML syntax is valid (use a YAML validator) - Verify file permissions allow reading

## Error: "model security entry not found" - Check that the model name in config.json matches exactly in .security.yml - Verify the model_list section exists in .security.yml - For indexed names (e.g., "gpt-5.4:0"), check both exact match and base name match - Ensure the YAML structure is correct (proper indentation)

## Multiple API Keys Not Working - Ensure you're using `api_keys` (plural) in .security.yml for models and web tools (except GLMSearch/BaiduSearch) - Check that the array format is correct in YAML (proper indentation with dashes) - Remember: Models, Brave, Tavily, Perplexity, Kagi MUST use `api_keys` (array format) - GLMSearch and BaiduSearch MUST use `api_key` (single string format)

## Keys Not Being Applied - Check that .security.yml is in the same directory as config.json - Verify the file permissions allow reading (chmod 600 ~/.facet-studio/.security.yml) - Ensure the YAML structure matches the expected format - Check for typos in field names (case-sensitive) - Verify the model/channel names match exactly (case-sensitive)

## Load Balancing/Failover Issues - Verify all API keys in the api_keys array are valid - Check that all keys have the same rate limits and permissions - Monitor logs to see which keys are being used and failing - Ensure the api_keys array is properly formatted in YAML

Index

Constants

View Source
const (
	ReadFileModeBytes = "bytes"
	ReadFileModeLines = "lines"
)
View Source
const (
	ChannelPico           = "pico"
	ChannelPicoClient     = "pico_client"
	ChannelTelegram       = "telegram"
	ChannelDiscord        = "discord"
	ChannelFeishu         = "feishu"
	ChannelWeixin         = "weixin"
	ChannelWeCom          = "wecom"
	ChannelDingTalk       = "dingtalk"
	ChannelSlack          = "slack"
	ChannelMatrix         = "matrix"
	ChannelDeltaChat      = "deltachat"
	ChannelLINE           = "line"
	ChannelOneBot         = "onebot"
	ChannelQQ             = "qq"
	ChannelIRC            = "irc"
	ChannelVK             = "vk"
	ChannelMaixCam        = "maixcam"
	ChannelWhatsApp       = "whatsapp"
	ChannelWhatsAppNative = "whatsapp_native"
	ChannelTeamsWebHook   = "teams_webhook"
	ChannelMQTT           = "mqtt"
	ChannelSlackWebHook   = "slack_webhook"
)

Channel type constants — single source of truth for all channel type names.

View Source
const (
	// EnvHome overrides the base directory for all facet-studio data
	// (config, workspace, skills, auth store, …).
	// Default: ~/.facet-studio
	EnvHome = "FACET_STUDIO_HOME"

	// EnvConfig overrides the full path to the JSON config file.
	// Default: $FACET_STUDIO_HOME/config.json
	EnvConfig = "FACET_STUDIO_CONFIG"

	// EnvBuiltinSkills overrides the directory from which built-in
	// skills are loaded.
	// Default: <cwd>/skills
	EnvBuiltinSkills = "FACET_STUDIO_BUILTIN_SKILLS"

	// EnvBinary overrides the path to the facet-studio executable.
	// Used by the web launcher when spawning the gateway subprocess.
	// Default: resolved from the same directory as the current executable.
	EnvBinary = "FACET_STUDIO_BINARY"

	// EnvGatewayHost overrides the host address for the gateway server.
	// Default: "localhost"
	EnvGatewayHost = "FACET_STUDIO_GATEWAY_HOST"
)

Runtime environment variable keys for the facet-studio process. These control the location of files and binaries at runtime and are read directly via os.Getenv / os.LookupEnv. All facet-studio-specific keys use the FACET_STUDIO_ prefix. Reference these constants instead of inline string literals to keep all supported knobs visible in one place and to prevent typos.

View Source
const CurrentVersion = 3

CurrentVersion is the latest config schema version

View Source
const DefaultGatewayLogLevel = "warn"
View Source
const DefaultMCPMaxInlineTextChars = 16 * 1024
View Source
const DefaultMaxMediaSize = 20 * 1024 * 1024 // 20 MB
View Source
const (
	SecurityConfigFile = ".security.yml"
)

Variables

View Source
var (
	Version   = "dev" // Default value when not built with ldflags
	GitCommit string  // Git commit SHA (short)
	BuildTime string  // Build timestamp in RFC3339 format
	GoVersion string  // Go version used for building
)

Build-time variables injected via ldflags during build process. These are set by the Makefile or .goreleaser.yaml using the -X flag:

-X github.com/xibodev/facet-studio/pkg/config.Version=<version>
-X github.com/xibodev/facet-studio/pkg/config.GitCommit=<commit>
-X github.com/xibodev/facet-studio/pkg/config.BuildTime=<timestamp>
-X github.com/xibodev/facet-studio/pkg/config.GoVersion=<go-version>
View Source
var BaseFieldNames = map[string]struct{}{
	"enabled":              {},
	"type":                 {},
	"allow_from":           {},
	"reasoning_channel_id": {},
	"group_trigger":        {},
	"typing":               {},
	"placeholder":          {},
}

BaseFieldNames are JSON keys that belong to Channel, not to channel-specific settings.

View Source
var DefaultEventLoggingInclude = []string{"agent.*"}

DefaultEventLoggingInclude keeps the pre-existing behavior where agent events are printed, while non-agent runtime events are published for subscribers only.

Functions

func DevHome

func DevHome() string

DevHome is the fallback for a binary running from a development checkout, where writing into the user profile by surprise is the wrong behaviour.

SEPARATE FROM GetHome ON PURPOSE. GetHome is where a real install keeps config, credentials, logs and workspace; changing ITS fallback would strand an existing install's state. This one answers a narrower question -- "am I a dev build, and if so where is my sandbox" -- and callers that want the developer behaviour ask for it explicitly.

Anchored to the EXECUTABLE rather than the working directory. Returning a bare ".local" resolves against wherever the process happens to be: run from anywhere but the repo root and `modules` reported "no modules installed" with modules sitting on disk, while `modules-add` copied into one directory and verified another. A confident wrong answer, reported by an author who lost an install to it.

func DiagnosticSummary

func DiagnosticSummary(err error) string

func EffectiveGatewayLogLevel

func EffectiveGatewayLogLevel(cfg *Config) string

EffectiveGatewayLogLevel returns the normalized runtime log level from a loaded config. Invalid or empty values fall back to the package default.

func EffectiveMCPTransportType

func EffectiveMCPTransportType(server MCPServerConfig) string

EffectiveMCPTransportType returns the normalized configured transport, or the inferred default when the config leaves Type empty.

func FormatBuildInfo

func FormatBuildInfo() (string, string)

FormatBuildInfo returns build time and go version info

func FormatVersion

func FormatVersion() string

FormatVersion returns the version string with optional git commit

func GetHome

func GetHome() string

GetHome is the ONE answer to "where is host state", and every part of the host must use it -- launcher, gateway, agent and CLI alike.

WHY THIS COMMENT EXISTS. There was a second implementation in the CLI with a DIFFERENT fallback, and the two only agreed when FACET_STUDIO_HOME was set. Unset, the CLI installed modules into an executable-anchored `.local` while the agent discovered from `~/.facet-studio` -- so `modules-add` succeeded, the CLI listed the module, and THE BROWSER AGENT SAW NOTHING. Discovery finding no modules is indistinguishable from none being installed, so it failed silently.

It went unnoticed because every launch during development set the variable explicitly, which masks the divergence completely.

This project has consolidated this exact class twice before -- once for module discovery and once for grants, both recorded in cmd/facet-studio. Those unified the FUNCTIONS and left the `home` argument fed into them as two implementations. Same bug, one level up.

func GetVersion

func GetVersion() string

GetVersion returns the version string

func InitChannelList

func InitChannelList(channels ChannelsConfig) error

InitChannelList validates and initializes all channels in the ChannelsConfig. It performs three steps:

  1. Validates that each channel has a non-empty Type
  2. Validates singleton constraints
  3. Decodes Settings into the correct typed struct based on Type, so that b.extend contains the actual settings (e.g., PicoSettings)

After calling this method, callers can safely use b.extend via Decode() without re-parsing raw Settings.

func IsDevBuild

func IsDevBuild() bool

IsDevBuild reports whether this binary is running from a development checkout rather than an installed location.

THE SINGLE PLACE THAT DECIDES, so the CLI and the host cannot answer it differently. The test is where the binary SITS: a build placed in a `.local` directory is a dev build, anything else is an install. That is the same signal DevHome already used to anchor itself, named once rather than re-derived by each caller.

An explicit FACET_STUDIO_HOME wins over both paths, so this only decides the fallback -- which is the only thing the two implementations ever disagreed about.

func IsSingletonChannel

func IsSingletonChannel(channelType string) bool

IsSingletonChannel returns true if the channel type only allows one instance.

func MakeBackup

func MakeBackup(path string) error

func NormalizeMCPTransportType

func NormalizeMCPTransportType(transport string) string

NormalizeMCPTransportType canonicalizes MCP transport names used in config. "http" is Facet Studio's streamable HTTP request-response mode, and "streamable-http" is accepted as an explicit alias for the same transport.

func RegisterChannelSettings

func RegisterChannelSettings(channelType string, prototype any)

RegisterChannelSettings registers a settings struct prototype for a custom channel type. External packages (out-of-tree channels registered via channels.RegisterFactory) call this from an init() so their channel type passes config validation (isValidChannelType) and its settings block decodes into the right struct (newChannelSettings). The prototype must be a struct value, e.g. RegisterChannelSettings("my_channel", MyChannelSettings{}).

func ResetToDefaults

func ResetToDefaults(configPath string) error

ResetToDefaults backs up the current config, creates a default config, preserves security credentials from the existing config, and saves it.

func ResolveGatewayLogLevel

func ResolveGatewayLogLevel(path string) string

ResolveGatewayLogLevel reads the configured gateway log level without triggering the full config loader, so startup code can apply logging before config load logs run. The FACET_STUDIO_LOG_LEVEL environment variable overrides the file value.

func SaveConfig

func SaveConfig(path string, cfg *Config) error

Types

type AgentConfig

type AgentConfig struct {
	ID        string            `json:"id"`
	Default   bool              `json:"default,omitempty"`
	Name      string            `json:"name,omitempty"`
	Workspace string            `json:"workspace,omitempty"`
	Model     *AgentModelConfig `json:"model,omitempty"`
	Skills    []string          `json:"skills,omitempty"`
	Subagents *SubagentsConfig  `json:"subagents,omitempty"`
}

type AgentDefaults

type AgentDefaults struct {
	Workspace                 string             `json:"workspace"                        env:"FACET_STUDIO_AGENTS_DEFAULTS_WORKSPACE"`
	RestrictToWorkspace       bool               `json:"restrict_to_workspace"            env:"FACET_STUDIO_AGENTS_DEFAULTS_RESTRICT_TO_WORKSPACE"`
	AllowReadOutsideWorkspace bool               `json:"allow_read_outside_workspace"     env:"FACET_STUDIO_AGENTS_DEFAULTS_ALLOW_READ_OUTSIDE_WORKSPACE"`
	Provider                  string             `json:"provider"                         env:"FACET_STUDIO_AGENTS_DEFAULTS_PROVIDER"`
	ModelName                 string             `json:"model_name"                       env:"FACET_STUDIO_AGENTS_DEFAULTS_MODEL_NAME"`
	ModelFallbacks            []string           `json:"model_fallbacks,omitempty"`
	ImageModel                string             `json:"image_model,omitempty"            env:"FACET_STUDIO_AGENTS_DEFAULTS_IMAGE_MODEL"`
	ImageModelFallbacks       []string           `json:"image_model_fallbacks,omitempty"`
	MaxTokens                 int                `json:"max_tokens"                       env:"FACET_STUDIO_AGENTS_DEFAULTS_MAX_TOKENS"`
	ContextWindow             int                `json:"context_window,omitempty"         env:"FACET_STUDIO_AGENTS_DEFAULTS_CONTEXT_WINDOW"`
	Temperature               *float64           `json:"temperature,omitempty"            env:"FACET_STUDIO_AGENTS_DEFAULTS_TEMPERATURE"`
	MaxToolIterations         int                `json:"max_tool_iterations"              env:"FACET_STUDIO_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
	SummarizeMessageThreshold int                `json:"summarize_message_threshold"      env:"FACET_STUDIO_AGENTS_DEFAULTS_SUMMARIZE_MESSAGE_THRESHOLD"`
	SummarizeTokenPercent     int                `json:"summarize_token_percent"          env:"FACET_STUDIO_AGENTS_DEFAULTS_SUMMARIZE_TOKEN_PERCENT"`
	MaxMediaSize              int                `json:"max_media_size,omitempty"         env:"FACET_STUDIO_AGENTS_DEFAULTS_MAX_MEDIA_SIZE"`
	Routing                   *RoutingConfig     `json:"routing,omitempty"`
	SteeringMode              string             `json:"steering_mode,omitempty"          env:"FACET_STUDIO_AGENTS_DEFAULTS_STEERING_MODE"`      // "one-at-a-time" (default) or "all"
	MaxParallelTurns          int                `json:"max_parallel_turns,omitempty"     env:"FACET_STUDIO_AGENTS_DEFAULTS_MAX_PARALLEL_TURNS"` // Max concurrent turns (0 or 1 = sequential)
	SubTurn                   SubTurnConfig      ``                                                                                              /* 149-byte string literal not displayed */
	ToolFeedback              ToolFeedbackConfig `json:"tool_feedback,omitempty"`
	SplitOnMarker             bool               `json:"split_on_marker"                  env:"FACET_STUDIO_AGENTS_DEFAULTS_SPLIT_ON_MARKER"` // split messages on <|[SPLIT]|> marker
	ContextManager            string             `json:"context_manager,omitempty"        env:"FACET_STUDIO_AGENTS_DEFAULTS_CONTEXT_MANAGER"`
	ContextManagerConfig      json.RawMessage    `json:"context_manager_config,omitempty" env:"FACET_STUDIO_AGENTS_DEFAULTS_CONTEXT_MANAGER_CONFIG"`
	TurnProfile               TurnProfileConfig  `json:"turn_profile,omitempty"`
	MaxLLMRetries             int                `json:"max_llm_retries,omitempty"        env:"FACET_STUDIO_AGENTS_DEFAULTS_MAX_LLM_RETRIES"`
	LLMRetryBackoffSecs       int                `json:"llm_retry_backoff_secs,omitempty" env:"FACET_STUDIO_AGENTS_DEFAULTS_LLM_RETRY_BACKOFF_SECS"`
}

func (*AgentDefaults) GetMaxMediaSize

func (d *AgentDefaults) GetMaxMediaSize() int

func (*AgentDefaults) GetModelName

func (d *AgentDefaults) GetModelName() string

GetModelName returns the effective model name for the agent defaults. It prefers the new "model_name" field but falls back to "model" for backward compatibility.

func (*AgentDefaults) GetToolFeedbackMaxArgsLength

func (d *AgentDefaults) GetToolFeedbackMaxArgsLength() int

GetToolFeedbackMaxArgsLength returns the max visible text length for tool argument previews.

func (*AgentDefaults) IsToolFeedbackEnabled

func (d *AgentDefaults) IsToolFeedbackEnabled() bool

IsToolFeedbackEnabled returns true when tool feedback messages should be sent to the chat.

func (*AgentDefaults) IsToolFeedbackSeparateMessagesEnabled

func (d *AgentDefaults) IsToolFeedbackSeparateMessagesEnabled() bool

IsToolFeedbackSeparateMessagesEnabled returns true when each tool feedback update should be sent as its own chat message instead of editing a single in-place progress message.

func (*AgentDefaults) ResolveTurnProfile

func (d *AgentDefaults) ResolveTurnProfile() (EffectiveTurnProfile, bool, error)

type AgentModelConfig

type AgentModelConfig struct {
	Primary   string   `json:"primary,omitempty"`
	Fallbacks []string `json:"fallbacks,omitempty"`
}

AgentModelConfig supports both string and structured model config. String format: "gpt-4" (just primary, no fallbacks) Object format: {"primary": "gpt-4", "fallbacks": ["claude-haiku"]}

func (AgentModelConfig) MarshalJSON

func (m AgentModelConfig) MarshalJSON() ([]byte, error)

func (*AgentModelConfig) UnmarshalJSON

func (m *AgentModelConfig) UnmarshalJSON(data []byte) error

type AgentsConfig

type AgentsConfig struct {
	Defaults AgentDefaults   `json:"defaults"`
	List     []AgentConfig   `json:"list,omitempty"`
	Dispatch *DispatchConfig `json:"dispatch,omitempty"`
}

type BaiduSearchConfig

type BaiduSearchConfig struct {
	Enabled    bool         `json:"enabled"          yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_BAIDU_ENABLED"`
	APIKey     SecureString `json:"api_key,omitzero" yaml:"api_key,omitempty" env:"FACET_STUDIO_TOOLS_WEB_BAIDU_API_KEY"`
	BaseURL    string       `json:"base_url"         yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_BAIDU_BASE_URL"`
	MaxResults int          `json:"max_results"      yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_BAIDU_MAX_RESULTS"`
}

type BraveConfig

type BraveConfig struct {
	Enabled    bool          `json:"enabled"           yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_BRAVE_ENABLED"`
	APIKeys    SecureStrings `json:"api_keys,omitzero" yaml:"api_keys,omitempty" env:"FACET_STUDIO_TOOLS_WEB_BRAVE_API_KEYS"`
	MaxResults int           `json:"max_results"       yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_BRAVE_MAX_RESULTS"`
}

func (*BraveConfig) APIKey

func (c *BraveConfig) APIKey() string

APIKey returns the Brave API key

func (*BraveConfig) SetAPIKey

func (c *BraveConfig) SetAPIKey(key string)

SetAPIKey sets the Brave API key

func (*BraveConfig) SetAPIKeys

func (c *BraveConfig) SetAPIKeys(keys []string)

type BuildInfo

type BuildInfo struct {
	Version   string `json:"version"`
	GitCommit string `json:"git_commit"`
	BuildTime string `json:"build_time"`
	GoVersion string `json:"go_version"`
}

BuildInfo contains build-time version information

type BuiltinHookConfig

type BuiltinHookConfig struct {
	Enabled  bool            `json:"enabled"`
	Priority int             `json:"priority,omitempty"`
	Config   json.RawMessage `json:"config,omitempty"`
}

type Channel

type Channel struct {
	Enabled            bool                `json:"enabled"                 yaml:"-"`
	Type               string              `json:"type"                    yaml:"-"`
	AllowFrom          FlexibleStringSlice `json:"allow_from,omitempty"    yaml:"-"`
	ReasoningChannelID string              `json:"reasoning_channel_id"    yaml:"-"`
	GroupTrigger       GroupTriggerConfig  `json:"group_trigger,omitempty" yaml:"-"`
	Typing             TypingConfig        `json:"typing,omitempty"        yaml:"-"`
	Placeholder        PlaceholderConfig   `json:"placeholder,omitempty"   yaml:"-"`
	Settings           RawNode             `json:"settings,omitzero"       yaml:"settings,omitempty"`
	// contains filtered or unexported fields
}

Channel defines the common fields shared by all channel types. Channel-specific settings go into Settings (nested format only). The settings struct should use SecureString/SecureStrings for sensitive fields.

Decode stores the settings pointer internally; subsequent modifications to the decoded struct are automatically reflected in MarshalJSON/MarshalYAML.

MarshalJSON outputs nested format (common fields at top level, settings as sub-key). MarshalYAML outputs only secure fields (for .security.yml).

Standard Go JSON/YAML unmarshaling handles nested format correctly:

  • JSON: {"enabled": true, "type": "telegram", "settings": {"base_url": "..."}}
  • YAML: settings: {token: xxx} (for .security.yml)

func (Channel) CollectSensitiveValues

func (b Channel) CollectSensitiveValues() []string

CollectSensitiveValues returns all sensitive string values from this Channel's decoded settings (extend). Used by the security filter system.

func (*Channel) Decode

func (b *Channel) Decode(target any) error

Decode decodes the Settings node into the given target struct and stores the pointer internally. Subsequent modifications to the target are automatically reflected in MarshalJSON/MarshalYAML (no explicit Encode needed).

func (*Channel) GetDecoded

func (b *Channel) GetDecoded() (any, error)

GetDecoded returns the previously decoded settings struct. If Decode hasn't been called yet, it lazily decodes using the channel Type prototype. Returns an error if decoding fails; the decoded value (possibly nil) is still returned so callers can distinguish between "not decoded" and "decode failed".

func (Channel) MarshalJSON

func (b Channel) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for Channel. Outputs nested format: common fields at top level, channel-specific in "settings". Secure fields (SecureString/SecureStrings) are removed from settings output.

func (Channel) MarshalYAML

func (b Channel) MarshalYAML() (any, error)

MarshalYAML implements yaml.ValueMarshaler for Channel. Outputs only secure fields in the Settings YAML (for .security.yml). If Decode was called, it serializes from the stored extend (reflecting any modifications); otherwise falls back to decoding Settings via the channel Type to extract secure fields.

func (*Channel) Name

func (b *Channel) Name() string

Name returns the channel name.

func (*Channel) SetName

func (b *Channel) SetName(name string)

SetName sets the channel name.

func (*Channel) SetSecretField

func (b *Channel) SetSecretField(fieldName string, value SecureString)

SetSecretField sets a secure field value by field name in the Settings JSON. NOTE: This only operates on raw Settings. If Decode() has been called, prefer modifying the typed struct directly — MarshalJSON serializes from extend.

func (*Channel) SettingsIsEmpty

func (b *Channel) SettingsIsEmpty() bool

SettingsIsEmpty returns true if Settings has not been populated.

func (*Channel) UnmarshalYAML

func (b *Channel) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML implements yaml.Unmarshaler for Channel. Merges the YAML node into the existing Channel. Supports both nested format (settings: {...}) and flat format (token: xxx).

type ChannelsConfig

type ChannelsConfig map[string]*Channel

ChannelsConfig maps channel name to its Channel configuration. Each Channel stores the full channel config in Settings and handles JSON/YAML serialization (removing/keeping secure fields automatically).

func (ChannelsConfig) Get

func (c ChannelsConfig) Get(name string) *Channel

Get returns the Channel for the given channel name (map key), or nil if not found.

func (ChannelsConfig) GetByType

func (c ChannelsConfig) GetByType(t string) *Channel

GetByType returns the Channel for the given channel type, or nil if not found.

func (ChannelsConfig) SetEnabled

func (c ChannelsConfig) SetEnabled(name string, enabled bool) bool

SetEnabled sets the Enabled field on the Channel with the given name. Returns false if no channel with that name exists.

func (*ChannelsConfig) UnmarshalJSON

func (c *ChannelsConfig) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler for ChannelsConfig. Sets the channel name from the map key after unmarshaling.

func (*ChannelsConfig) UnmarshalYAML

func (c *ChannelsConfig) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML implements yaml.Unmarshaler for ChannelsConfig. This ensures that when loading security.yml, existing Channel instances are properly merged rather than replaced with new ones.

type Config

type Config struct {
	// Config schema version for migration.
	Version   int             `json:"version"             yaml:"-"`
	Isolation IsolationConfig `json:"isolation,omitempty" yaml:"-"`
	Agents    AgentsConfig    `json:"agents"              yaml:"-"`
	Session   SessionConfig   `json:"session,omitempty"   yaml:"-"`
	Evolution EvolutionConfig `json:"evolution,omitempty" yaml:"-"`
	Channels  ChannelsConfig  `json:"channel_list"        yaml:"channel_list"`
	ModelList SecureModelList `json:"model_list"          yaml:"model_list"` // New model-centric provider configuration
	// ProviderInstances and ModelRoutes are the instance-owned provider
	// foundation. Legacy ModelList remains authoritative until a later migration.
	ProviderInstances []*ProviderInstanceConfig `json:"provider_instances,omitempty" yaml:"-"`
	ModelRoutes       []*ModelRouteConfig       `json:"model_routes,omitempty"       yaml:"-"`
	ActiveModels      []string                  `json:"active_models,omitempty"      yaml:"-"`
	Gateway           GatewayConfig             `json:"gateway"             yaml:"-"`
	Events            EventsConfig              `json:"events,omitempty"    yaml:"-"`
	Hooks             HooksConfig               `json:"hooks,omitempty"     yaml:"-"`
	Tools             ToolsConfig               `json:"tools"               yaml:",inline"`
	Heartbeat         HeartbeatConfig           `json:"heartbeat"           yaml:"-"`
	Devices           DevicesConfig             `json:"devices"             yaml:"-"`
	Voice             VoiceConfig               `json:"voice"               yaml:"-"`
	// BuildInfo contains build-time version information
	BuildInfo BuildInfo `json:"build_info,omitempty" yaml:"-"`
	// contains filtered or unexported fields
}

Config is the current config structure with version support.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns the default configuration for Facet Studio.

func LoadConfig

func LoadConfig(path string) (*Config, error)

func (*Config) FilterSensitiveData

func (c *Config) FilterSensitiveData(content string) string

FilterSensitiveData filters sensitive values from content before sending to LLM. This prevents the LLM from seeing its own credentials. Uses strings.Replacer for O(n+m) performance (computed once per SecurityConfig). Short content (below FilterMinLength) is returned unchanged for performance.

func (*Config) GetModelConfig

func (c *Config) GetModelConfig(modelName string) (*ModelConfig, error)

GetModelConfig returns the ModelConfig for the given model name. If multiple configs exist with the same model_name, it uses round-robin selection for load balancing. Returns an error if the model is not found.

func (*Config) MarshalJSON

func (c *Config) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling for Config to omit providers section when empty and session when empty.

func (*Config) SecurityCopyFrom

func (c *Config) SecurityCopyFrom(path string) error

func (*Config) SensitiveDataReplacer

func (sec *Config) SensitiveDataReplacer() *strings.Replacer

SensitiveDataReplacer returns the strings.Replacer for filtering sensitive data. It is computed once on first access via sync.Once.

func (*Config) ValidateModelList

func (c *Config) ValidateModelList() error

ValidateModelList validates all ModelConfig entries in the model_list. It checks that each model config is valid. Note: Multiple entries with the same model_name are allowed for load balancing.

func (*Config) ValidateProviderInstances

func (c *Config) ValidateProviderInstances() error

func (*Config) ValidateTurnProfile

func (c *Config) ValidateTurnProfile() error

func (*Config) WorkspacePath

func (c *Config) WorkspacePath() string

type CronToolsConfig

type CronToolsConfig struct {
	ToolConfig `envPrefix:"FACET_STUDIO_TOOLS_CRON_"`
	// 0 means no timeout.
	ExecTimeoutMinutes    int      `json:"exec_timeout_minutes"    env:"FACET_STUDIO_TOOLS_CRON_EXEC_TIMEOUT_MINUTES"`
	AllowCommand          bool     `json:"allow_command"           env:"FACET_STUDIO_TOOLS_CRON_ALLOW_COMMAND"`
	CommandAllowedRemotes []string `json:"command_allowed_remotes" env:"FACET_STUDIO_TOOLS_CRON_COMMAND_ALLOWED_REMOTES"`
}

type DeltaChatSettings

type DeltaChatSettings struct {
	Email          string       `json:"email"                     yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_EMAIL"`
	Password       SecureString `json:"password,omitzero"         yaml:"password,omitempty" env:"FACET_STUDIO_CHANNELS_DELTACHAT_PASSWORD"`
	DisplayName    string       `json:"display_name,omitempty"    yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_DISPLAY_NAME"`
	AvatarImage    string       `json:"avatar_image,omitempty"    yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_AVATAR_IMAGE"`
	DataDir        string       `json:"data_dir,omitempty"        yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_DATA_DIR"`
	RPCServerPath  string       `json:"rpc_server_path,omitempty" yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_RPC_SERVER_PATH"`
	InviteLink     string       `json:"invite_link,omitempty"     yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_INVITE_LINK"`
	AllowCrosspost bool         `json:"allow_crosspost,omitempty" yaml:"-"                  env:"FACET_STUDIO_CHANNELS_DELTACHAT_ALLOW_CROSSPOST"`
	IMAPServer     string       `json:"imap_server,omitempty"     yaml:"-"`
	IMAPPort       int          `json:"imap_port,omitempty"       yaml:"-"`
	SMTPServer     string       `json:"smtp_server,omitempty"     yaml:"-"`
	SMTPPort       int          `json:"smtp_port,omitempty"       yaml:"-"`
}

DeltaChatSettings configures the Delta Chat channel. Delta Chat is an email-based, end-to-end encrypted messenger; Facet Studio talks to a local `deltachat-rpc-server` process over JSON-RPC (stdio).

Email is the only required setting. A full address selects an already configured account in DataDir; a first-run marker such as "@nine.testrun.org" creates a chatmail account and tells the user which full email to save. Mailbox credentials stay in the Delta Chat account store. DisplayName and AvatarImage are optional profile settings applied on startup. Password remains only for legacy Facet Studio-managed email configuration.

type DevicesConfig

type DevicesConfig struct {
	Enabled    bool `json:"enabled"     env:"FACET_STUDIO_DEVICES_ENABLED"`
	MonitorUSB bool `json:"monitor_usb" env:"FACET_STUDIO_DEVICES_MONITOR_USB"`
}

type DingTalkSettings

type DingTalkSettings struct {
	ClientID     string       `json:"client_id"              yaml:"-"                       env:"FACET_STUDIO_CHANNELS_DINGTALK_CLIENT_ID"`
	ClientSecret SecureString `json:"client_secret,omitzero" yaml:"client_secret,omitempty" env:"FACET_STUDIO_CHANNELS_DINGTALK_CLIENT_SECRET"`
}

type DiscordSettings

type DiscordSettings struct {
	Token       SecureString `json:"token,omitzero" yaml:"token,omitempty" env:"FACET_STUDIO_CHANNELS_DISCORD_TOKEN"`
	Proxy       string       `json:"proxy"          yaml:"-"               env:"FACET_STUDIO_CHANNELS_DISCORD_PROXY"`
	MentionOnly bool         `json:"mention_only"   yaml:"-"               env:"FACET_STUDIO_CHANNELS_DISCORD_MENTION_ONLY"`
}

type DispatchConfig

type DispatchConfig struct {
	Rules []DispatchRule `json:"rules,omitempty"`
}

type DispatchRule

type DispatchRule struct {
	Name              string           `json:"name,omitempty"`
	Agent             string           `json:"agent"`
	When              DispatchSelector `json:"when"`
	SessionDimensions []string         `json:"session_dimensions,omitempty"`
}

type DispatchSelector

type DispatchSelector struct {
	Channel   string `json:"channel,omitempty"`
	Account   string `json:"account,omitempty"`
	Space     string `json:"space,omitempty"`
	Chat      string `json:"chat,omitempty"`
	Topic     string `json:"topic,omitempty"`
	Sender    string `json:"sender,omitempty"`
	Mentioned *bool  `json:"mentioned,omitempty"`
}

type DuckDuckGoConfig

type DuckDuckGoConfig struct {
	Enabled    bool `json:"enabled"     env:"FACET_STUDIO_TOOLS_WEB_DUCKDUCKGO_ENABLED"`
	MaxResults int  `json:"max_results" env:"FACET_STUDIO_TOOLS_WEB_DUCKDUCKGO_MAX_RESULTS"`
}

type EffectiveTurnProfile

type EffectiveTurnProfile struct {
	Enabled          bool
	HistoryMode      TurnProfileMode
	SystemPromptMode TurnProfileMode
	SkillsMode       TurnProfileMode
	ToolsMode        TurnProfileMode
	AllowedSkills    []string
	AllowedTools     []string
}

type EventLoggingConfig

type EventLoggingConfig struct {
	// Enabled controls whether runtime events are printed by the built-in logger.
	Enabled bool `json:"enabled" env:"ENABLED"`
	// Include contains exact event kinds or glob patterns such as "agent.*" or "*".
	Include []string `json:"include,omitempty" env:"INCLUDE"`
	// Exclude contains exact event kinds or glob patterns to suppress after Include matches.
	Exclude []string `json:"exclude,omitempty" env:"EXCLUDE"`
	// MinSeverity filters out events below the configured severity: debug, info, warn, or error.
	MinSeverity string `json:"min_severity,omitempty" env:"MIN_SEVERITY"`
	// IncludePayload adds the raw payload to logs. Leave disabled unless detailed diagnostics are needed.
	IncludePayload bool `json:"include_payload,omitempty" env:"INCLUDE_PAYLOAD"`
}

EventLoggingConfig controls centralized runtime event logging.

func EffectiveEventLoggingConfig

func EffectiveEventLoggingConfig(cfg *Config) EventLoggingConfig

EffectiveEventLoggingConfig returns a logging config with stable defaults.

type EventsConfig

type EventsConfig struct {
	Logging EventLoggingConfig `json:"logging,omitempty" envPrefix:"FACET_STUDIO_EVENTS_LOGGING_"`
}

EventsConfig groups runtime event configuration.

type EvolutionConfig

type EvolutionConfig struct {
	Enabled         bool     `json:"enabled,omitempty"`
	Mode            string   `json:"mode,omitempty"`
	StateDir        string   `json:"state_dir,omitempty"`
	MinTaskCount    int      `json:"min_task_count,omitempty"`
	MinSuccessRatio float64  `json:"min_success_ratio,omitempty"`
	ColdPathTrigger string   `json:"cold_path_trigger,omitempty"`
	ColdPathTimes   []string `json:"cold_path_times,omitempty"`
	// Deprecated: use MinTaskCount.
	MinCaseCount int `json:"min_case_count,omitempty"`
	// Deprecated: use MinSuccessRatio.
	MinSuccessRate float64 `json:"min_success_rate,omitempty"`
}

func (EvolutionConfig) AutoAppliesDrafts

func (c EvolutionConfig) AutoAppliesDrafts() bool

func (EvolutionConfig) ColdPathTriggerMode

func (c EvolutionConfig) ColdPathTriggerMode() string

func (EvolutionConfig) EffectiveColdPathTimes

func (c EvolutionConfig) EffectiveColdPathTimes() []string

func (EvolutionConfig) EffectiveMinSuccessRatio

func (c EvolutionConfig) EffectiveMinSuccessRatio() float64

func (EvolutionConfig) EffectiveMinTaskCount

func (c EvolutionConfig) EffectiveMinTaskCount() int

func (EvolutionConfig) EffectiveMode

func (c EvolutionConfig) EffectiveMode() string

func (EvolutionConfig) MarshalJSON

func (c EvolutionConfig) MarshalJSON() ([]byte, error)

func (EvolutionConfig) RunsColdPathAfterTurn

func (c EvolutionConfig) RunsColdPathAfterTurn() bool

func (EvolutionConfig) RunsColdPathAutomatically

func (c EvolutionConfig) RunsColdPathAutomatically() bool

func (EvolutionConfig) RunsColdPathScheduled

func (c EvolutionConfig) RunsColdPathScheduled() bool

type ExactModelTarget

type ExactModelTarget struct {
	InstanceID string
	ModelID    string
}

ExactModelTarget identifies one model owned by one configured provider instance. ModelID may contain additional slashes.

func ParseExactModelTarget

func ParseExactModelTarget(raw string) (ExactModelTarget, error)

func (ExactModelTarget) String

func (t ExactModelTarget) String() string

type ExecConfig

type ExecConfig struct {
	ToolConfig          `         envPrefix:"FACET_STUDIO_TOOLS_EXEC_"`
	EnableDenyPatterns  bool     `                                 json:"enable_deny_patterns"  env:"FACET_STUDIO_TOOLS_EXEC_ENABLE_DENY_PATTERNS"`
	AllowRemote         bool     `                                 json:"allow_remote"          env:"FACET_STUDIO_TOOLS_EXEC_ALLOW_REMOTE"`
	CustomDenyPatterns  []string `                                 json:"custom_deny_patterns"  env:"FACET_STUDIO_TOOLS_EXEC_CUSTOM_DENY_PATTERNS"`
	CustomAllowPatterns []string `                                 json:"custom_allow_patterns" env:"FACET_STUDIO_TOOLS_EXEC_CUSTOM_ALLOW_PATTERNS"`
	TimeoutSeconds      int      `                                 json:"timeout_seconds"       env:"FACET_STUDIO_TOOLS_EXEC_TIMEOUT_SECONDS"` // 0 means use default (60s)
}

type ExposePath

type ExposePath struct {
	Source string `json:"source"`
	Target string `json:"target,omitempty"`
	Mode   string `json:"mode"`
}

ExposePath describes a host path that should remain visible inside the isolated child-process environment. This is currently implemented on Linux only.

type FeishuSettings

type FeishuSettings struct {
	AppID               string              `json:"app_id"                      yaml:"-"                            env:"FACET_STUDIO_CHANNELS_FEISHU_APP_ID"`
	AppSecret           SecureString        `json:"app_secret,omitzero"         yaml:"app_secret,omitempty"         env:"FACET_STUDIO_CHANNELS_FEISHU_APP_SECRET"`
	EncryptKey          SecureString        `json:"encrypt_key,omitzero"        yaml:"encrypt_key,omitempty"        env:"FACET_STUDIO_CHANNELS_FEISHU_ENCRYPT_KEY"`
	VerificationToken   SecureString        `json:"verification_token,omitzero" yaml:"verification_token,omitempty" env:"FACET_STUDIO_CHANNELS_FEISHU_VERIFICATION_TOKEN"`
	RandomReactionEmoji FlexibleStringSlice `` /* 127-byte string literal not displayed */
	IsLark              bool                `json:"is_lark"                     yaml:"-"                            env:"FACET_STUDIO_CHANNELS_FEISHU_IS_LARK"`
}

type FlexibleStringSlice

type FlexibleStringSlice []string

FlexibleStringSlice is a []string that also accepts JSON numbers, so allow_from can contain both "123" and 123. It also supports parsing comma-separated strings from environment variables, including both English (,) and Chinese (,) commas.

func (*FlexibleStringSlice) UnmarshalJSON

func (f *FlexibleStringSlice) UnmarshalJSON(data []byte) error

func (*FlexibleStringSlice) UnmarshalText

func (f *FlexibleStringSlice) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler to support env variable parsing. It handles comma-separated values with both English (,) and Chinese (,) commas.

type GLMSearchConfig

type GLMSearchConfig struct {
	Enabled bool         `json:"enabled"          yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_GLM_ENABLED"`
	APIKey  SecureString `json:"api_key,omitzero" yaml:"api_key,omitempty" env:"FACET_STUDIO_TOOLS_WEB_GLM_API_KEY"`
	BaseURL string       `json:"base_url"         yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_GLM_BASE_URL"`
	// SearchEngine specifies the search backend: "search_std" (default),
	// "search_pro", "search_pro_sogou", or "search_pro_quark".
	SearchEngine string `json:"search_engine" yaml:"-" env:"FACET_STUDIO_TOOLS_WEB_GLM_SEARCH_ENGINE"`
	MaxResults   int    `json:"max_results"   yaml:"-" env:"FACET_STUDIO_TOOLS_WEB_GLM_MAX_RESULTS"`
}

type GatewayConfig

type GatewayConfig struct {
	Host      string `json:"host"                env:"FACET_STUDIO_GATEWAY_HOST"`
	Port      int    `json:"port"                env:"FACET_STUDIO_GATEWAY_PORT"`
	HotReload bool   `json:"hot_reload"          env:"FACET_STUDIO_GATEWAY_HOT_RELOAD"`
	LogLevel  string `json:"log_level,omitempty" env:"FACET_STUDIO_LOG_LEVEL"`
}

type GeminiSearchConfig

type GeminiSearchConfig struct {
	Enabled    bool         `json:"enabled"          yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_GEMINI_ENABLED"`
	APIKey     SecureString `json:"api_key,omitzero" yaml:"api_key,omitempty" env:"FACET_STUDIO_TOOLS_WEB_GEMINI_API_KEY"`
	Model      string       `json:"model"            yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_GEMINI_MODEL"`
	MaxResults int          `json:"max_results"      yaml:"-"                 env:"FACET_STUDIO_TOOLS_WEB_GEMINI_MAX_RESULTS"`
}

type GroupTriggerConfig

type GroupTriggerConfig struct {
	MentionOnly bool     `json:"mention_only,omitempty"`
	Prefixes    []string `json:"prefixes,omitempty"`
}

GroupTriggerConfig controls when the bot responds in group chats.

type HeartbeatConfig

type HeartbeatConfig struct {
	Enabled  bool `json:"enabled"  env:"FACET_STUDIO_HEARTBEAT_ENABLED"`
	Interval int  `json:"interval" env:"FACET_STUDIO_HEARTBEAT_INTERVAL"` // minutes, min 5
}

type HookDefaultsConfig

type HookDefaultsConfig struct {
	ObserverTimeoutMS    int `json:"observer_timeout_ms,omitempty"`
	InterceptorTimeoutMS int `json:"interceptor_timeout_ms,omitempty"`
	ApprovalTimeoutMS    int `json:"approval_timeout_ms,omitempty"`
}

type HooksConfig

type HooksConfig struct {
	Enabled   bool                         `json:"enabled"`
	Defaults  HookDefaultsConfig           `json:"defaults,omitempty"`
	Builtins  map[string]BuiltinHookConfig `json:"builtins,omitempty"`
	Processes map[string]ProcessHookConfig `json:"processes,omitempty"`
}

type IRCSettings

type IRCSettings struct {
	Server           string              `json:"server"                     yaml:"-"                           env:"FACET_STUDIO_CHANNELS_IRC_SERVER"`
	TLS              bool                `json:"tls"                        yaml:"-"                           env:"FACET_STUDIO_CHANNELS_IRC_TLS"`
	Nick             string              `json:"nick"                       yaml:"-"                           env:"FACET_STUDIO_CHANNELS_IRC_NICK"`
	User             string              `json:"user,omitempty"             yaml:"-"                           env:"FACET_STUDIO_CHANNELS_IRC_USER"`
	RealName         string              `json:"real_name,omitempty"        yaml:"-"`
	Password         SecureString        `json:"password,omitzero"          yaml:"password,omitempty"          env:"FACET_STUDIO_CHANNELS_IRC_PASSWORD"`
	NickServPassword SecureString        `json:"nickserv_password,omitzero" yaml:"nickserv_password,omitempty" env:"FACET_STUDIO_CHANNELS_IRC_NICKSERV_PASSWORD"`
	SASLUser         string              `json:"sasl_user"                  yaml:"-"                           env:"FACET_STUDIO_CHANNELS_IRC_SASL_USER"`
	SASLPassword     SecureString        `json:"sasl_password,omitzero"     yaml:"sasl_password,omitempty"     env:"FACET_STUDIO_CHANNELS_IRC_SASL_PASSWORD"`
	Channels         FlexibleStringSlice `json:"channels"                   yaml:"-"                           env:"FACET_STUDIO_CHANNELS_IRC_CHANNELS"`
	RequestCaps      FlexibleStringSlice `json:"request_caps,omitempty"     yaml:"-"`
}

type IsolationConfig

type IsolationConfig struct {
	Enabled     bool         `json:"enabled,omitempty"`
	ExposePaths []ExposePath `json:"expose_paths,omitempty"`
}

IsolationConfig controls subprocess isolation for commands started by Facet Studio. It is applied by the isolation package rather than by sandboxing the main process.

type KagiConfig

type KagiConfig struct {
	Enabled    bool          `json:"enabled"           yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_KAGI_ENABLED"`
	APIKeys    SecureStrings `json:"api_keys,omitzero" yaml:"api_keys,omitempty" env:"FACET_STUDIO_TOOLS_WEB_KAGI_API_KEYS"`
	BaseURL    string        `json:"base_url"          yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_KAGI_BASE_URL"`
	MaxResults int           `json:"max_results"       yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_KAGI_MAX_RESULTS"`
}

func (*KagiConfig) APIKey

func (c *KagiConfig) APIKey() string

APIKey returns the Kagi API key

func (*KagiConfig) SetAPIKey

func (c *KagiConfig) SetAPIKey(key string)

SetAPIKey sets the Kagi API key

func (*KagiConfig) SetAPIKeys

func (c *KagiConfig) SetAPIKeys(keys []string)

SetAPIKeys sets the Kagi API keys

type LINESettings

type LINESettings struct {
	ChannelSecret      SecureString `json:"channel_secret,omitzero"       yaml:"channel_secret,omitempty"       env:"FACET_STUDIO_CHANNELS_LINE_CHANNEL_SECRET"`
	ChannelAccessToken SecureString `` /* 128-byte string literal not displayed */
	WebhookHost        string       `json:"webhook_host"                  yaml:"-"                              env:"FACET_STUDIO_CHANNELS_LINE_WEBHOOK_HOST"`
	WebhookPort        int          `json:"webhook_port"                  yaml:"-"                              env:"FACET_STUDIO_CHANNELS_LINE_WEBHOOK_PORT"`
	WebhookPath        string       `json:"webhook_path"                  yaml:"-"                              env:"FACET_STUDIO_CHANNELS_LINE_WEBHOOK_PATH"`
}

type MCPConfig

type MCPConfig struct {
	ToolConfig `                    envPrefix:"FACET_STUDIO_TOOLS_MCP_"`
	Discovery  ToolDiscoveryConfig `                                json:"discovery"`
	// MaxInlineTextChars controls how much MCP text stays inline before it is saved as an artifact.
	MaxInlineTextChars int `json:"max_inline_text_chars,omitempty" env:"FACET_STUDIO_TOOLS_MCP_MAX_INLINE_TEXT_CHARS"`
	// Servers is a map of server name to server configuration
	Servers map[string]MCPServerConfig `json:"servers,omitempty"`
}

MCPConfig defines configuration for all MCP servers

func (*MCPConfig) GetMaxInlineTextChars

func (c *MCPConfig) GetMaxInlineTextChars() int

type MCPServerConfig

type MCPServerConfig struct {
	// Enabled indicates whether this MCP server is active
	Enabled bool `json:"enabled"`
	// Deferred controls whether this server's tools are registered as hidden (deferred/discovery mode).
	// When nil, the global Discovery.Enabled setting applies.
	// When explicitly set to true or false, it overrides the global setting for this server only.
	Deferred *bool `json:"deferred,omitempty"`
	// Command is the executable to run (e.g., "npx", "python", "/path/to/server")
	Command string `json:"command"`
	// Args are the arguments to pass to the command
	Args []string `json:"args,omitempty"`
	// Env are environment variables to set for the server process (stdio only)
	Env map[string]string `json:"env,omitempty"`
	// EnvFile is the path to a file containing environment variables (stdio only)
	EnvFile string `json:"env_file,omitempty"`
	// Type is "stdio", "sse", "http", or "streamable-http".
	// "http" and "streamable-http" both select streamable HTTP request-response
	// mode, while "sse" keeps the standalone SSE listener enabled for
	// server-initiated notifications. Defaults: stdio if command is set, sse if
	// url is set.
	Type string `json:"type,omitempty"`
	// URL is used for SSE/HTTP transport
	URL string `json:"url,omitempty"`
	// Headers are HTTP headers to send with requests (sse/http only)
	Headers map[string]string `json:"headers,omitempty"`
}

MCPServerConfig defines configuration for a single MCP server

type MQTTSettings

type MQTTSettings struct {
	Broker      string       `json:"broker"                 yaml:"-"                  env:"FACET_STUDIO_CHANNELS_MQTT_BROKER"`
	AgentID     string       `json:"agent_id"               yaml:"-"                  env:"FACET_STUDIO_CHANNELS_MQTT_AGENT_ID"`
	TopicPrefix string       `json:"topic_prefix,omitempty" yaml:"-"                  env:"FACET_STUDIO_CHANNELS_MQTT_TOPIC_PREFIX"`
	Username    SecureString `json:"username,omitzero"      yaml:"username,omitempty" env:"FACET_STUDIO_CHANNELS_MQTT_USERNAME"`
	Password    SecureString `json:"password,omitzero"      yaml:"password,omitempty" env:"FACET_STUDIO_CHANNELS_MQTT_PASSWORD"`
	ClientID    string       `json:"client_id,omitempty"    yaml:"-"                  env:"FACET_STUDIO_CHANNELS_MQTT_CLIENT_ID"`
	KeepAlive   int          `json:"keep_alive,omitempty"   yaml:"-"                  env:"FACET_STUDIO_CHANNELS_MQTT_KEEP_ALIVE"`
	QoS         int          `json:"qos,omitempty"          yaml:"-"                  env:"FACET_STUDIO_CHANNELS_MQTT_QOS"`
}

type MaixCamSettings

type MaixCamSettings struct {
	Host string `json:"host" yaml:"-" env:"FACET_STUDIO_CHANNELS_MAIXCAM_HOST"`
	Port int    `json:"port" yaml:"-" env:"FACET_STUDIO_CHANNELS_MAIXCAM_PORT"`
}

type MatrixSettings

type MatrixSettings struct {
	Homeserver         string       `json:"homeserver"                     yaml:"-"                      env:"FACET_STUDIO_CHANNELS_MATRIX_HOMESERVER"`
	UserID             string       `json:"user_id"                        yaml:"-"                      env:"FACET_STUDIO_CHANNELS_MATRIX_USER_ID"`
	AccessToken        SecureString `json:"access_token,omitzero"          yaml:"access_token,omitempty" env:"FACET_STUDIO_CHANNELS_MATRIX_ACCESS_TOKEN"`
	DeviceID           string       `json:"device_id,omitempty"            yaml:"-"`
	JoinOnInvite       bool         `json:"join_on_invite"                 yaml:"-"`
	MessageFormat      string       `json:"message_format,omitempty"       yaml:"-"`
	CryptoDatabasePath string       `json:"crypto_database_path,omitempty" yaml:"-"`
	CryptoPassphrase   string       `json:"crypto_passphrase,omitempty"    yaml:"-"`
}

type MediaCleanupConfig

type MediaCleanupConfig struct {
	ToolConfig `    envPrefix:"FACET_STUDIO_MEDIA_CLEANUP_"`
	MaxAge     int `                                    json:"max_age_minutes"  env:"FACET_STUDIO_MEDIA_CLEANUP_MAX_AGE"`
	Interval   int `                                    json:"interval_minutes" env:"FACET_STUDIO_MEDIA_CLEANUP_INTERVAL"`
}

type MessageToolsConfig

type MessageToolsConfig struct {
	ToolConfig `yaml:"-" envPrefix:"FACET_STUDIO_TOOLS_MESSAGE_"`

	MediaEnabled bool `json:"media_enabled" yaml:"-" env:"FACET_STUDIO_TOOLS_MESSAGE_MEDIA_ENABLED"`
}

type ModelConfig

type ModelConfig struct {
	// Required fields
	ModelName string `json:"model_name"` // User-facing alias for the model
	Provider  string `json:"provider"`   // Provider name for routing and selection. When empty, provider resolution infers it from Model.
	Model     string `json:"model"`      // Model identifier, optionally provider-prefixed.

	// HTTP-based providers
	APIBase   string   `json:"api_base,omitempty"`  // API endpoint URL
	Proxy     string   `json:"proxy,omitempty"`     // HTTP proxy URL
	Fallbacks []string `json:"fallbacks,omitempty"` // Fallback model names for failover

	// Special providers (CLI-based, OAuth, etc.)
	AuthMethod  string `json:"auth_method,omitempty"`  // Authentication method: oauth, token
	ConnectMode string `json:"connect_mode,omitempty"` // Connection mode: stdio, grpc
	Workspace   string `json:"workspace,omitempty"`    // Workspace path for CLI-based providers

	// Optional optimizations
	RPM                 int                  `json:"rpm,omitempty"`              // Requests per minute limit
	MaxTokensField      string               `json:"max_tokens_field,omitempty"` // Field name for max tokens (e.g., "max_completion_tokens")
	RequestTimeout      int                  `json:"request_timeout,omitempty"`
	ThinkingLevel       string               `json:"thinking_level,omitempty"`        // Extended thinking: off|low|medium|high|xhigh|adaptive
	ToolSchemaTransform string               `json:"tool_schema_transform,omitempty"` // Optional tool schema compatibility transform (e.g. "simple")
	Streaming           ModelStreamingConfig `json:"streaming,omitzero"`              // Opt-in for provider streaming on this model entry
	ExtraBody           map[string]any       `json:"extra_body,omitempty"`            // Additional fields to inject into request body
	CustomHeaders       map[string]string    `json:"custom_headers,omitempty"`        // Additional headers to inject into every HTTP request

	APIKeys SecureStrings `json:"api_keys,omitzero" yaml:"api_keys,omitempty"` // API authentication keys (multiple keys for failover)

	// Enabled indicates whether this model entry is active. When omitted in
	// existing configs, the field is inferred during load: models with API keys
	// or the reserved "local-model" name are auto-enabled.
	Enabled bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
	// UserAgent is the user agent string to use for HTTP requests.
	UserAgent string `json:"user_agent,omitempty" yaml:"-"`
	// contains filtered or unexported fields
}

ModelConfig represents a model-centric provider configuration. It allows adding new providers (especially OpenAI-compatible ones) via configuration only. The Model field may be either a plain model identifier or a provider-prefixed identifier such as "openai/gpt-5.4" or "nvidia/z-ai/glm-5.1". Supported providers include openai, anthropic, antigravity, claude-cli, codex-cli, github-copilot, and named OpenAI-compatible protocols such as groq, deepseek, modelscope, and novita.

func (*ModelConfig) APIKey

func (c *ModelConfig) APIKey() string

APIKey returns the first API key from apiKeys

func (*ModelConfig) IsVirtual

func (c *ModelConfig) IsVirtual() bool

IsVirtual returns true if this model was generated from multi-key expansion.

func (*ModelConfig) SetAPIKey

func (c *ModelConfig) SetAPIKey(value string)

func (*ModelConfig) Validate

func (c *ModelConfig) Validate() error

Validate checks if the ModelConfig has all required fields.

type ModelRouteConfig

type ModelRouteConfig struct {
	Name    string   `json:"name"`
	Targets []string `json:"targets"`
}

ModelRouteConfig is an ordered failover route of exact instance-owned targets. Ordering is significant and duplicates are invalid.

type ModelStreamingConfig

type ModelStreamingConfig struct {
	Enabled bool `json:"enabled,omitempty"`
}

func (ModelStreamingConfig) IsZero

func (c ModelStreamingConfig) IsZero() bool

type OneBotSettings

type OneBotSettings struct {
	WSUrl              string       `json:"ws_url"                yaml:"-"                      env:"FACET_STUDIO_CHANNELS_ONEBOT_WS_URL"`
	AccessToken        SecureString `json:"access_token,omitzero" yaml:"access_token,omitempty" env:"FACET_STUDIO_CHANNELS_ONEBOT_ACCESS_TOKEN"`
	ReconnectInterval  int          `json:"reconnect_interval"    yaml:"-"                      env:"FACET_STUDIO_CHANNELS_ONEBOT_RECONNECT_INTERVAL"`
	GroupTriggerPrefix []string     `json:"group_trigger_prefix"  yaml:"-"                      env:"FACET_STUDIO_CHANNELS_ONEBOT_GROUP_TRIGGER_PREFIX"`
}

type PerplexityConfig

type PerplexityConfig struct {
	Enabled    bool          `json:"enabled"           yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_PERPLEXITY_ENABLED"`
	APIKeys    SecureStrings `json:"api_keys,omitzero" yaml:"api_keys,omitempty" env:"FACET_STUDIO_TOOLS_WEB_PERPLEXITY_API_KEYS"`
	MaxResults int           `json:"max_results"       yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_PERPLEXITY_MAX_RESULTS"`
}

func (*PerplexityConfig) APIKey

func (c *PerplexityConfig) APIKey() string

APIKey returns the Perplexity API key

func (*PerplexityConfig) SetAPIKey

func (c *PerplexityConfig) SetAPIKey(key string)

SetAPIKey sets the Perplexity API key

type PicoClientSettings

type PicoClientSettings struct {
	URL          string       `json:"url"                     yaml:"-"               env:"FACET_STUDIO_CHANNELS_PICO_CLIENT_URL"`
	Token        SecureString `json:"token,omitzero"          yaml:"token,omitempty" env:"FACET_STUDIO_CHANNELS_PICO_CLIENT_TOKEN"`
	SessionID    string       `json:"session_id,omitempty"    yaml:"-"`
	PingInterval int          `json:"ping_interval,omitempty" yaml:"-"`
	ReadTimeout  int          `json:"read_timeout,omitempty"  yaml:"-"`
}

type PicoSettings

type PicoSettings struct {
	Token           SecureString    `json:"token,omitzero"              yaml:"token,omitempty" env:"FACET_STUDIO_CHANNELS_PICO_TOKEN"`
	AllowTokenQuery bool            `json:"allow_token_query,omitempty" yaml:"-"`
	AllowOrigins    []string        `json:"allow_origins,omitempty"     yaml:"-"`
	Streaming       StreamingConfig `json:"streaming,omitzero"          yaml:"-"`
	PingInterval    int             `json:"ping_interval,omitempty"     yaml:"-"`
	ReadTimeout     int             `json:"read_timeout,omitempty"      yaml:"-"`
	WriteTimeout    int             `json:"write_timeout,omitempty"     yaml:"-"`
	MaxConnections  int             `json:"max_connections,omitempty"   yaml:"-"`
}

func (*PicoSettings) SetToken

func (c *PicoSettings) SetToken(token string)

SetToken sets the Pico token and marks it as dirty for security saving

type PlaceholderConfig

type PlaceholderConfig struct {
	Enabled bool                `json:"enabled"`
	Text    FlexibleStringSlice `json:"text,omitempty"`
}

PlaceholderConfig controls placeholder message behavior (Phase 10).

func (*PlaceholderConfig) GetRandomText

func (p *PlaceholderConfig) GetRandomText() string

GetRandomText returns a random placeholder text, or default if none set.

type ProcessHookConfig

type ProcessHookConfig struct {
	Enabled   bool              `json:"enabled"`
	Priority  int               `json:"priority,omitempty"`
	Transport string            `json:"transport,omitempty"`
	Command   []string          `json:"command,omitempty"`
	Dir       string            `json:"dir,omitempty"`
	Env       map[string]string `json:"env,omitempty"`
	Observe   []string          `json:"observe,omitempty"`
	Intercept []string          `json:"intercept,omitempty"`
}

type ProviderInstanceConfig

type ProviderInstanceConfig struct {
	ID                string                `json:"id"`
	ProviderKind      string                `json:"provider_kind"`
	Adapter           string                `json:"adapter"`
	Protocol          string                `json:"protocol"`
	Endpoint          string                `json:"endpoint,omitempty"`
	AuthConnectionRef string                `json:"auth_connection_ref,omitempty"`
	Headers           map[string]string     `json:"headers,omitempty"`
	Settings          map[string]any        `json:"settings,omitempty"`
	State             ProviderInstanceState `json:"state"`
}

ProviderInstanceConfig owns one provider adapter connection independently of any model selected from its catalog.

func (*ProviderInstanceConfig) Validate

func (c *ProviderInstanceConfig) Validate() error

type ProviderInstanceState

type ProviderInstanceState string
const (
	ProviderInstanceStateEnabled  ProviderInstanceState = "enabled"
	ProviderInstanceStateDisabled ProviderInstanceState = "disabled"
)

type QQSettings

type QQSettings struct {
	AppID                string       `json:"app_id"                   yaml:"-"                    env:"FACET_STUDIO_CHANNELS_QQ_APP_ID"`
	AppSecret            SecureString `json:"app_secret,omitzero"      yaml:"app_secret,omitempty" env:"FACET_STUDIO_CHANNELS_QQ_APP_SECRET"`
	MaxMessageLength     int          `json:"max_message_length"       yaml:"-"                    env:"FACET_STUDIO_CHANNELS_QQ_MAX_MESSAGE_LENGTH"`
	MaxBase64FileSizeMiB int64        `json:"max_base64_file_size_mib" yaml:"-"                    env:"FACET_STUDIO_CHANNELS_QQ_MAX_BASE64_FILE_SIZE_MIB"`
	SendMarkdown         bool         `json:"send_markdown"            yaml:"-"                    env:"FACET_STUDIO_CHANNELS_QQ_SEND_MARKDOWN"`
}

type RawNode

type RawNode json.RawMessage

RawNode stores raw configuration data as JSON bytes, supporting both JSON and YAML. Internally uses json.RawMessage, so Decode always uses json.Unmarshal which correctly respects json struct tags.

func (*RawNode) Decode

func (r *RawNode) Decode(target any) error

Decode unmarshals the stored data into the given target struct using json.Unmarshal.

func (*RawNode) IsEmpty

func (r *RawNode) IsEmpty() bool

IsEmpty returns true if the node has not been populated.

func (RawNode) MarshalJSON

func (r RawNode) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler: outputs stored JSON bytes.

func (RawNode) MarshalYAML

func (r RawNode) MarshalYAML() (any, error)

MarshalYAML implements yaml.ValueMarshaler: converts stored JSON back to a YAML-compatible value.

func (*RawNode) UnmarshalJSON

func (r *RawNode) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler: stores raw JSON bytes. NOTE: yaml.Unmarshal may call this when unmarshaling into RawNode fields. We detect if the input looks like YAML (not JSON) and handle it.

func (*RawNode) UnmarshalYAML

func (r *RawNode) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML implements yaml.Unmarshaler: converts YAML node to JSON bytes. Merges the incoming YAML values with existing data, with YAML taking precedence.

type ReadFileToolConfig

type ReadFileToolConfig struct {
	Enabled         bool   `json:"enabled"`
	Mode            string `json:"mode"`
	MaxReadFileSize int    `json:"max_read_file_size"`
}

func (ReadFileToolConfig) EffectiveMode

func (c ReadFileToolConfig) EffectiveMode() string

type RoutingConfig

type RoutingConfig struct {
	Enabled    bool    `json:"enabled"`
	LightModel string  `json:"light_model"` // model_name from model_list to use for simple tasks
	Threshold  float64 `json:"threshold"`   // complexity score in [0,1]; score >= threshold → primary model
}

RoutingConfig controls the intelligent model routing feature. When enabled, each incoming message is scored against structural features (message length, code blocks, tool call history, conversation depth, attachments). Messages scoring below Threshold are sent to LightModel; all others use the agent's primary model. This reduces cost and latency for simple tasks without requiring any keyword matching — all scoring is language-agnostic.

type SearXNGConfig

type SearXNGConfig struct {
	Enabled    bool   `json:"enabled"     env:"FACET_STUDIO_TOOLS_WEB_SEARXNG_ENABLED"`
	BaseURL    string `json:"base_url"    env:"FACET_STUDIO_TOOLS_WEB_SEARXNG_BASE_URL"`
	MaxResults int    `json:"max_results" env:"FACET_STUDIO_TOOLS_WEB_SEARXNG_MAX_RESULTS"`
}

type SearchCacheConfig

type SearchCacheConfig struct {
	MaxSize    int `json:"max_size"    env:"FACET_STUDIO_SKILLS_SEARCH_CACHE_MAX_SIZE"`
	TTLSeconds int `json:"ttl_seconds" env:"FACET_STUDIO_SKILLS_SEARCH_CACHE_TTL_SECONDS"`
}

type SecureModelList

type SecureModelList []*ModelConfig

func (SecureModelList) MarshalYAML

func (v SecureModelList) MarshalYAML() (any, error)

func (*SecureModelList) UnmarshalYAML

func (v *SecureModelList) UnmarshalYAML(value *yaml.Node) error

type SecureString

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

SecureString the string value that can be decrypted or resolved

func NewSecureString

func NewSecureString(value string) *SecureString

func (SecureString) IsZero

func (s SecureString) IsZero() bool

IsZero returns true if the SecureString is empty if caller not yaml, just return true for prevent marshal this field

func (SecureString) MarshalJSON

func (s SecureString) MarshalJSON() ([]byte, error)

func (SecureString) MarshalYAML

func (s SecureString) MarshalYAML() (any, error)

func (*SecureString) Set

func (s *SecureString) Set(value string) *SecureString

func (*SecureString) String

func (s *SecureString) String() string

func (*SecureString) UnmarshalJSON

func (s *SecureString) UnmarshalJSON(value []byte) error

func (*SecureString) UnmarshalText

func (s *SecureString) UnmarshalText(text []byte) error

func (*SecureString) UnmarshalYAML

func (s *SecureString) UnmarshalYAML(value *yaml.Node) error

type SecureStrings

type SecureStrings []*SecureString

SecureStrings is a slice of SecureString

func SimpleSecureStrings

func SimpleSecureStrings(val ...string) SecureStrings

func (SecureStrings) IsZero

func (s SecureStrings) IsZero() bool

IsZero returns true if the SecureStrings is nil or empty.

func (SecureStrings) MarshalJSON

func (s SecureStrings) MarshalJSON() ([]byte, error)

func (*SecureStrings) UnmarshalJSON

func (s *SecureStrings) UnmarshalJSON(value []byte) error

func (*SecureStrings) Values

func (s *SecureStrings) Values() []string

Values returns the decrypted/resolved values

type SensitiveDataCache

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

SensitiveDataCache caches the strings.Replacer for filtering sensitive data. Computed once on first access via sync.Once.

type SessionConfig

type SessionConfig struct {
	Dimensions    []string            `json:"dimensions,omitempty"`
	IdentityLinks map[string][]string `json:"identity_links,omitempty"`
	DmScope       string              `json:"dm_scope,omitempty"`
}

func (*SessionConfig) ApplyDmScope

func (s *SessionConfig) ApplyDmScope()

ApplyDmScope translates the user-facing dm_scope value into the internal dimensions array that the routing layer consumes. It is a no-op when DmScope is empty or when Dimensions is already set (explicit Dimensions take precedence over the derived value).

func (*SessionConfig) DeriveDmScope

func (s *SessionConfig) DeriveDmScope()

DeriveDmScope sets DmScope based on Dimensions when DmScope is empty. This handles legacy/fresh configs that only have explicit Dimensions without a corresponding DmScope value, ensuring the API response always includes a dm_scope that matches the actual runtime dimensions.

type SkillRegistryConfig

type SkillRegistryConfig struct {
	Name      string         `json:"name,omitempty"      yaml:"-"                    env:"-"`
	Enabled   bool           `json:"enabled"             yaml:"-"                    env:"-"`
	BaseURL   string         `json:"base_url"            yaml:"-"                    env:"-"`
	AuthToken SecureString   `json:"auth_token,omitzero" yaml:"auth_token,omitempty" env:"-"`
	Param     map[string]any `json:"-"                   yaml:"-"                    env:"-"`
}

func (*SkillRegistryConfig) DecodeParam

func (c *SkillRegistryConfig) DecodeParam(target any) error

func (SkillRegistryConfig) MarshalJSON

func (c SkillRegistryConfig) MarshalJSON() ([]byte, error)

func (SkillRegistryConfig) MarshalYAML

func (c SkillRegistryConfig) MarshalYAML() (any, error)

func (*SkillRegistryConfig) UnmarshalJSON

func (c *SkillRegistryConfig) UnmarshalJSON(data []byte) error

func (*SkillRegistryConfig) UnmarshalYAML

func (c *SkillRegistryConfig) UnmarshalYAML(value *yaml.Node) error

type SkillsGithubConfig

type SkillsGithubConfig struct {
	BaseURL string       `json:"base_url,omitempty" yaml:"-"               env:"FACET_STUDIO_TOOLS_SKILLS_GITHUB_BASE_URL"`
	Token   SecureString `json:"token,omitzero"     yaml:"token,omitempty" env:"FACET_STUDIO_TOOLS_SKILLS_GITHUB_TOKEN"`
	Proxy   string       `json:"proxy,omitempty"    yaml:"-"               env:"FACET_STUDIO_TOOLS_SKILLS_GITHUB_PROXY"`
}

type SkillsRegistriesConfig

type SkillsRegistriesConfig []*SkillRegistryConfig

func (*SkillsRegistriesConfig) Get

func (SkillsRegistriesConfig) MarshalJSON

func (v SkillsRegistriesConfig) MarshalJSON() ([]byte, error)

func (SkillsRegistriesConfig) MarshalYAML

func (v SkillsRegistriesConfig) MarshalYAML() (any, error)

func (*SkillsRegistriesConfig) Set

func (*SkillsRegistriesConfig) UnmarshalJSON

func (v *SkillsRegistriesConfig) UnmarshalJSON(data []byte) error

func (*SkillsRegistriesConfig) UnmarshalYAML

func (v *SkillsRegistriesConfig) UnmarshalYAML(value *yaml.Node) error

type SkillsToolsConfig

type SkillsToolsConfig struct {
	ToolConfig `                       yaml:"-"                    envPrefix:"FACET_STUDIO_TOOLS_SKILLS_"`
	Registries SkillsRegistriesConfig `yaml:"registries,omitempty"                                    json:"registries"`
	// Deprecated: use registries.github instead.
	Github                SkillsGithubConfig `yaml:"github,omitempty" json:"github"`
	MaxConcurrentSearches int                `yaml:"-"                json:"max_concurrent_searches" env:"FACET_STUDIO_TOOLS_SKILLS_MAX_CONCURRENT_SEARCHES"`
	SearchCache           SearchCacheConfig  `yaml:"-"                json:"search_cache"`
}

type SlackSettings

type SlackSettings struct {
	BotToken SecureString `json:"bot_token,omitzero" yaml:"bot_token,omitempty" env:"FACET_STUDIO_CHANNELS_SLACK_BOT_TOKEN"`
	AppToken SecureString `json:"app_token,omitzero" yaml:"app_token,omitempty" env:"FACET_STUDIO_CHANNELS_SLACK_APP_TOKEN"`
}

type SlackWebhookSettings

type SlackWebhookSettings struct {
	Webhooks map[string]SlackWebhookTarget `json:"webhooks" yaml:"webhooks,omitempty"`
}

SlackWebhookSettings configures the output-only Slack webhook channel.

type SlackWebhookTarget

type SlackWebhookTarget struct {
	WebhookURL SecureString `json:"webhook_url,omitzero" yaml:"webhook_url,omitempty"`
	Username   string       `json:"username,omitempty"   yaml:"-"`
	IconEmoji  string       `json:"icon_emoji,omitempty" yaml:"-"`
}

SlackWebhookTarget represents a single Slack Incoming Webhook destination.

type SogouConfig

type SogouConfig struct {
	Enabled    bool `json:"enabled"     env:"FACET_STUDIO_TOOLS_WEB_SOGOU_ENABLED"`
	MaxResults int  `json:"max_results" env:"FACET_STUDIO_TOOLS_WEB_SOGOU_MAX_RESULTS"`
}

type StreamingConfig

type StreamingConfig struct {
	Enabled         bool `json:"enabled,omitempty"`
	ThrottleSeconds int  `json:"throttle_seconds,omitempty"`
	MinGrowthChars  int  `json:"min_growth_chars,omitempty"`
}

func (StreamingConfig) IsZero

func (c StreamingConfig) IsZero() bool

func (StreamingConfig) WithDefaults

func (c StreamingConfig) WithDefaults(throttleSeconds, minGrowthChars int) StreamingConfig

type SubTurnConfig

type SubTurnConfig struct {
	MaxDepth              int `json:"max_depth"               env:"FACET_STUDIO_AGENTS_DEFAULTS_SUBTURN_MAX_DEPTH"`
	MaxConcurrent         int `json:"max_concurrent"          env:"FACET_STUDIO_AGENTS_DEFAULTS_SUBTURN_MAX_CONCURRENT"`
	DefaultTimeoutMinutes int `json:"default_timeout_minutes" env:"FACET_STUDIO_AGENTS_DEFAULTS_SUBTURN_DEFAULT_TIMEOUT_MINUTES"`
	DefaultTokenBudget    int `json:"default_token_budget"    env:"FACET_STUDIO_AGENTS_DEFAULTS_SUBTURN_DEFAULT_TOKEN_BUDGET"`
	ConcurrencyTimeoutSec int `json:"concurrency_timeout_sec" env:"FACET_STUDIO_AGENTS_DEFAULTS_SUBTURN_CONCURRENCY_TIMEOUT_SEC"`
}

SubTurnConfig configures the SubTurn execution system.

type SubagentsConfig

type SubagentsConfig struct {
	AllowAgents []string          `json:"allow_agents,omitempty"`
	Model       *AgentModelConfig `json:"model,omitempty"`
}

type TavilyConfig

type TavilyConfig struct {
	Enabled    bool          `json:"enabled"           yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_TAVILY_ENABLED"`
	APIKeys    SecureStrings `json:"api_keys,omitzero" yaml:"api_keys,omitempty" env:"FACET_STUDIO_TOOLS_WEB_TAVILY_API_KEYS"`
	BaseURL    string        `json:"base_url"          yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_TAVILY_BASE_URL"`
	MaxResults int           `json:"max_results"       yaml:"-"                  env:"FACET_STUDIO_TOOLS_WEB_TAVILY_MAX_RESULTS"`
}

func (*TavilyConfig) APIKey

func (c *TavilyConfig) APIKey() string

APIKey returns the Tavily API key

func (*TavilyConfig) SetAPIKey

func (c *TavilyConfig) SetAPIKey(key string)

SetAPIKey sets the Tavily API key

func (*TavilyConfig) SetAPIKeys

func (c *TavilyConfig) SetAPIKeys(keys []string)

SetAPIKeys sets the Tavily API keys

type TeamsWebhookSettings

type TeamsWebhookSettings struct {
	Webhooks map[string]TeamsWebhookTarget `json:"webhooks" yaml:"webhooks,omitempty"`
}

TeamsWebhookSettings configures the output-only Microsoft Teams webhook channel. Multiple webhook targets can be configured and selected via ChatID at send time.

type TeamsWebhookTarget

type TeamsWebhookTarget struct {
	WebhookURL SecureString `json:"webhook_url,omitzero" yaml:"webhook_url,omitempty"`
	Title      string       `json:"title,omitempty"      yaml:"-"`
}

TeamsWebhookTarget represents a single Teams webhook destination.

type TelegramSettings

type TelegramSettings struct {
	Token             SecureString    `json:"token,omitzero"       yaml:"token,omitempty" env:"FACET_STUDIO_CHANNELS_TELEGRAM_TOKEN"`
	BaseURL           string          `json:"base_url"             yaml:"-"               env:"FACET_STUDIO_CHANNELS_TELEGRAM_BASE_URL"`
	Proxy             string          `json:"proxy"                yaml:"-"               env:"FACET_STUDIO_CHANNELS_TELEGRAM_PROXY"`
	Streaming         StreamingConfig `json:"streaming,omitzero"   yaml:"-"`
	UseMarkdownV2     bool            `json:"use_markdown_v2"      yaml:"-"               env:"FACET_STUDIO_CHANNELS_TELEGRAM_USE_MARKDOWN_V2"`
	MediaGroupDelayMS int             `json:"media_group_delay_ms" yaml:"-"               env:"FACET_STUDIO_CHANNELS_TELEGRAM_MEDIA_GROUP_DELAY_MS"`
}

type ToolConfig

type ToolConfig struct {
	Enabled bool `json:"enabled" yaml:"-" env:"ENABLED"`
}

type ToolDiscoveryConfig

type ToolDiscoveryConfig struct {
	Enabled          bool `json:"enabled"            env:"FACET_STUDIO_TOOLS_DISCOVERY_ENABLED"`
	TTL              int  `json:"ttl"                env:"FACET_STUDIO_TOOLS_DISCOVERY_TTL"`
	MaxSearchResults int  `json:"max_search_results" env:"FACET_STUDIO_MAX_SEARCH_RESULTS"`
	UseBM25          bool `json:"use_bm25"           env:"FACET_STUDIO_TOOLS_DISCOVERY_USE_BM25"`
	UseRegex         bool `json:"use_regex"          env:"FACET_STUDIO_TOOLS_DISCOVERY_USE_REGEX"`
}

type ToolFeedbackConfig

type ToolFeedbackConfig struct {
	Enabled          bool `json:"enabled"           env:"FACET_STUDIO_AGENTS_DEFAULTS_TOOL_FEEDBACK_ENABLED"`
	MaxArgsLength    int  `json:"max_args_length"   env:"FACET_STUDIO_AGENTS_DEFAULTS_TOOL_FEEDBACK_MAX_ARGS_LENGTH"`
	SeparateMessages bool `json:"separate_messages" env:"FACET_STUDIO_AGENTS_DEFAULTS_TOOL_FEEDBACK_SEPARATE_MESSAGES"`
}

type ToolsConfig

type ToolsConfig struct {
	AllowReadPaths  []string `json:"allow_read_paths"  yaml:"-" env:"FACET_STUDIO_TOOLS_ALLOW_READ_PATHS"`
	AllowWritePaths []string `json:"allow_write_paths" yaml:"-" env:"FACET_STUDIO_TOOLS_ALLOW_WRITE_PATHS"`
	// FilterSensitiveData controls whether to filter sensitive values (API keys,
	// tokens, secrets) from tool results before sending to the LLM.
	// Default: true (enabled)
	FilterSensitiveData bool `json:"filter_sensitive_data" yaml:"-" env:"FACET_STUDIO_TOOLS_FILTER_SENSITIVE_DATA"`
	// FilterMinLength is the minimum content length required for filtering.
	// Content shorter than this will be returned unchanged for performance.
	// Default: 8
	FilterMinLength int                `json:"filter_min_length" yaml:"-"                env:"FACET_STUDIO_TOOLS_FILTER_MIN_LENGTH"`
	Web             WebToolsConfig     `json:"web"               yaml:"web,omitempty"`
	Cron            CronToolsConfig    `json:"cron"              yaml:"-"`
	Exec            ExecConfig         `json:"exec"              yaml:"-"`
	Skills          SkillsToolsConfig  `json:"skills"            yaml:"skills,omitempty"`
	MediaCleanup    MediaCleanupConfig `json:"media_cleanup"     yaml:"-"`
	MCP             MCPConfig          `json:"mcp"               yaml:"-"`
	AppendFile      ToolConfig         `` /* 131-byte string literal not displayed */
	EditFile        ToolConfig         `` /* 129-byte string literal not displayed */
	FindSkills      ToolConfig         `` /* 131-byte string literal not displayed */
	I2C             ToolConfig         `json:"i2c"               yaml:"-"                                                       envPrefix:"FACET_STUDIO_TOOLS_I2C_"`
	InstallSkill    ToolConfig         `` /* 133-byte string literal not displayed */
	ListDir         ToolConfig         `` /* 128-byte string literal not displayed */
	LoadImage       ToolConfig         `` /* 130-byte string literal not displayed */
	Message         MessageToolsConfig `json:"message"           yaml:"-"`
	ReadFile        ReadFileToolConfig `` /* 129-byte string literal not displayed */
	Serial          ToolConfig         `` /* 126-byte string literal not displayed */
	SendFile        ToolConfig         `` /* 129-byte string literal not displayed */
	SendTTS         ToolConfig         `` /* 128-byte string literal not displayed */
	Spawn           ToolConfig         `json:"spawn"             yaml:"-"                                                       envPrefix:"FACET_STUDIO_TOOLS_SPAWN_"`
	SpawnStatus     ToolConfig         `` /* 132-byte string literal not displayed */
	SPI             ToolConfig         `json:"spi"               yaml:"-"                                                       envPrefix:"FACET_STUDIO_TOOLS_SPI_"`
	Subagent        ToolConfig         `` /* 128-byte string literal not displayed */
	WebFetch        ToolConfig         `` /* 129-byte string literal not displayed */
	WriteFile       ToolConfig         `` /* 130-byte string literal not displayed */
}

func (*ToolsConfig) GetFilterMinLength

func (c *ToolsConfig) GetFilterMinLength() int

GetFilterMinLength returns the minimum content length for filtering (default: 8)

func (*ToolsConfig) IsFilterSensitiveDataEnabled

func (c *ToolsConfig) IsFilterSensitiveDataEnabled() bool

IsFilterSensitiveDataEnabled returns true if sensitive data filtering is enabled

func (*ToolsConfig) IsToolEnabled

func (t *ToolsConfig) IsToolEnabled(name string) bool

type TurnProfileBlock

type TurnProfileBlock struct {
	Mode  TurnProfileMode `json:"mode,omitempty"`
	Allow []string        `json:"allow,omitempty"`
}

type TurnProfileConfig

type TurnProfileConfig struct {
	Enabled      bool             `json:"enabled"`
	History      TurnProfileBlock `json:"history,omitempty"`
	SystemPrompt TurnProfileBlock `json:"system_prompt,omitempty"`
	Skills       TurnProfileBlock `json:"skills,omitempty"`
	Tools        TurnProfileBlock `json:"tools,omitempty"`
}

type TurnProfileMode

type TurnProfileMode string
const (
	TurnProfileModeDefault TurnProfileMode = "default"
	TurnProfileModeOff     TurnProfileMode = "off"
	TurnProfileModeCustom  TurnProfileMode = "custom"
)

func (TurnProfileMode) Effective

func (m TurnProfileMode) Effective() TurnProfileMode

type TypingConfig

type TypingConfig struct {
	Enabled bool `json:"enabled,omitempty"`
}

TypingConfig controls typing indicator behavior (Phase 10).

type VKSettings

type VKSettings struct {
	Token   SecureString `json:"token,omitzero" yaml:"token,omitempty" env:"FACET_STUDIO_CHANNELS_VK_TOKEN"`
	GroupID int          `json:"group_id"       yaml:"-"               env:"FACET_STUDIO_CHANNELS_VK_GROUP_ID"`
}

func (*VKSettings) SetToken

func (c *VKSettings) SetToken(token string)

type VoiceConfig

type VoiceConfig struct {
	ModelName         string `json:"model_name,omitempty"         env:"FACET_STUDIO_VOICE_MODEL_NAME"`
	TTSModelName      string `json:"tts_model_name,omitempty"     env:"FACET_STUDIO_VOICE_TTS_MODEL_NAME"`
	EchoTranscription bool   `json:"echo_transcription"           env:"FACET_STUDIO_VOICE_ECHO_TRANSCRIPTION"`
	ElevenLabsAPIKey  string `json:"elevenlabs_api_key,omitempty" env:"FACET_STUDIO_VOICE_ELEVENLABS_API_KEY"`
}

type WeComGroupConfig

type WeComGroupConfig struct {
	AllowFrom FlexibleStringSlice `json:"allow_from,omitempty"`
}

type WeComSettings

type WeComSettings struct {
	BotID               string          `json:"bot_id"                  yaml:"-"                env:"BOT_ID"`
	Secret              SecureString    `json:"secret,omitzero"         yaml:"secret,omitempty" env:"SECRET"`
	WebSocketURL        string          `json:"websocket_url,omitempty" yaml:"-"                env:"WEBSOCKET_URL"`
	SendThinkingMessage bool            `json:"send_thinking_message"   yaml:"-"                env:"SEND_THINKING_MESSAGE"`
	Streaming           StreamingConfig `json:"streaming,omitzero"      yaml:"-"`
}

func (*WeComSettings) SetSecret

func (c *WeComSettings) SetSecret(secret string)

type WebToolsConfig

type WebToolsConfig struct {
	ToolConfig  `                   yaml:"-"                      envPrefix:"FACET_STUDIO_TOOLS_WEB_"`
	Brave       BraveConfig        `yaml:"brave,omitempty"                                        json:"brave"`
	Tavily      TavilyConfig       `yaml:"tavily,omitempty"                                       json:"tavily"`
	Kagi        KagiConfig         `yaml:"kagi,omitempty"                                         json:"kagi"`
	Sogou       SogouConfig        `yaml:"-"                                                      json:"sogou"`
	DuckDuckGo  DuckDuckGoConfig   `yaml:"-"                                                      json:"duckduckgo"`
	Gemini      GeminiSearchConfig `yaml:"gemini,omitempty"                                       json:"gemini"`
	Perplexity  PerplexityConfig   `yaml:"perplexity,omitempty"                                   json:"perplexity"`
	SearXNG     SearXNGConfig      `yaml:"-"                                                      json:"searxng"`
	GLMSearch   GLMSearchConfig    `yaml:"glm_search,omitempty"                                   json:"glm_search"`
	BaiduSearch BaiduSearchConfig  `yaml:"baidu_search,omitempty"                                 json:"baidu_search"`
	Provider    string             `yaml:"-"                                                      json:"provider,omitempty" env:"FACET_STUDIO_TOOLS_WEB_PROVIDER"`
	// PreferNative controls whether to use provider-native web search when
	// the active LLM supports it (e.g. OpenAI web_search_preview). When true,
	// the client-side web_search tool is hidden to avoid duplicate search surfaces,
	// and the provider's built-in search is used instead. Falls back to client-side
	// search when the provider does not support native search.
	PreferNative bool `yaml:"-" json:"prefer_native" env:"FACET_STUDIO_TOOLS_WEB_PREFER_NATIVE"`
	// Proxy is an optional proxy URL for web tools (http/https/socks5/socks5h).
	// For authenticated proxies, prefer HTTP_PROXY/HTTPS_PROXY env vars instead of embedding credentials in config.
	Proxy                string              `yaml:"-" json:"proxy,omitempty"                  env:"FACET_STUDIO_TOOLS_WEB_PROXY"`
	FetchLimitBytes      int64               `yaml:"-" json:"fetch_limit_bytes,omitempty"      env:"FACET_STUDIO_TOOLS_WEB_FETCH_LIMIT_BYTES"`
	Format               string              `yaml:"-" json:"format,omitempty"                 env:"FACET_STUDIO_TOOLS_WEB_FORMAT"`
	PrivateHostWhitelist FlexibleStringSlice `yaml:"-" json:"private_host_whitelist,omitempty" env:"FACET_STUDIO_TOOLS_WEB_PRIVATE_HOST_WHITELIST"`
}

type WeixinSettings

type WeixinSettings struct {
	Token      SecureString `json:"token,omitzero"       yaml:"token,omitempty" env:"FACET_STUDIO_CHANNELS_WEIXIN_TOKEN"`
	AccountID  string       `json:"account_id,omitempty" yaml:"-"               env:"FACET_STUDIO_CHANNELS_WEIXIN_ACCOUNT_ID"`
	BaseURL    string       `json:"base_url"             yaml:"-"               env:"FACET_STUDIO_CHANNELS_WEIXIN_BASE_URL"`
	CDNBaseURL string       `json:"cdn_base_url"         yaml:"-"               env:"FACET_STUDIO_CHANNELS_WEIXIN_CDN_BASE_URL"`
	Proxy      string       `json:"proxy"                yaml:"-"               env:"FACET_STUDIO_CHANNELS_WEIXIN_PROXY"`
}

func (*WeixinSettings) SetToken

func (c *WeixinSettings) SetToken(token string)

SetToken sets the Weixin token and marks it as dirty for security saving

type WhatsAppSettings

type WhatsAppSettings struct {
	BridgeURL        string `json:"bridge_url"         yaml:"-" env:"FACET_STUDIO_CHANNELS_WHATSAPP_BRIDGE_URL"`
	UseNative        bool   `json:"use_native"         yaml:"-" env:"FACET_STUDIO_CHANNELS_WHATSAPP_USE_NATIVE"`
	SessionStorePath string `json:"session_store_path" yaml:"-" env:"FACET_STUDIO_CHANNELS_WHATSAPP_SESSION_STORE_PATH"`
}

Jump to

Keyboard shortcuts

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