- A2:interrupt 新增 scope({"","all","current"}),三态语义 + 非法值定向 bad_request;
session_interrupted 形状零变化但 dropped 恒为真丢弃数
- G2:stream:true 直达编排器;响应面补 202 {queued} / 409 chat_busy / 503 chat_dispatch_failed;
未接 loop 由 200 改 500 chat_unavailable(行为变更已写明兼容性)
- G3:image 解码后 5 MiB 上限 → 400 image_too_large(指路上传);**如实写明 WS 侧到不了这条判定**
(wsReadLimit=4096 传输层直接断连,发真实图片必须「上传 + URL」)
- G4:新增可选 clientMsgId(两端)⇒ 幂等;REST 200 {duplicate:true,messageId}、WS 新帧 chat_duplicate
(owner+admin,fail-closed);键回填进 message_persisted/channel_persisted/读接口;迁移 0013
- .env.example + api-client 新增三个环境变量:OWNER_IDENTITY_INJECTION(owner_only 默认) /
CONTEXT_MAX_TOKENS(32768;0/负 = 关) / GUARDRAIL_KEYWORDS(留空 = 不挂)
- 修正两处错误陈述:api-reference §6.2 与 §6.6 的「OnStream 只填 seq、不带 turnId」(v0.36 起即带
sessionId+turnId,v0.50 起带 streamId);上传上限 50MB → 5 MiB
249 lines
15 KiB
Bash
249 lines
15 KiB
Bash
# ============================================
|
||
# Cyrene v2 配置文件 (.env)
|
||
# 复制为 .env 后修改。所有配置均从环境变量注入,代码内禁硬编码。
|
||
# 注意:.env 仅用于本地开发;生产用 systemd / env_file。
|
||
# 敏感信息(API Key / JWT_SECRET)一律不要写进日志。
|
||
# ============================================
|
||
|
||
# ---- 运行环境 ----
|
||
ENV=development
|
||
LOG_LEVEL=debug
|
||
TZ=Asia/Shanghai
|
||
|
||
# ---- 数据目录(裁决 12.4.2/15.4.1,design/13 §2) ----
|
||
# 两种取法都实现:默认 ./data;显式写 platform(保留字哨兵)则走平台标准数据目录
|
||
# (Windows %APPDATA%\Cyrene、macOS ~/Library/Application Support/Cyrene、Linux ~/.local/share/cyrene)。
|
||
DATA_DIR=./data
|
||
|
||
# ---- 服务器(网关,唯一对外端口) ----
|
||
# HOST 默认 0.0.0.0,暴露面由 .env 决定(本机自托管要收紧就改 127.0.0.1)。
|
||
HOST=0.0.0.0
|
||
PORT=8080
|
||
# 管理面板的安全入口路径(裁决 1.6/16.4.7,design/07 §0.2):
|
||
# 管理面板前端挂在这个路径下,默认 admin(即 /admin);想藏起来就自定义,例如
|
||
# ADMIN_PATH=my-secret/admin → 面板在 /my-secret/admin,猜 /admin 直接 404。
|
||
# 它只影响面板前端路由;REST 仍是 /api/v1/admin/*(API 不藏,安全靠 JWT + 角色门),
|
||
# 且该路径串不会出现在用户端页面里。
|
||
ADMIN_PATH=admin
|
||
|
||
# ---- 认证 / 管理员 ----
|
||
# JWT_SECRET 必填,长度 >= 32;缺失或过短会在启动时 panic。
|
||
JWT_SECRET=change-me-to-a-random-string-at-least-32-characters
|
||
ADMIN_USERNAME=admin
|
||
ADMIN_PASSWORD=admin12345
|
||
REGISTRATION_ENABLED=true
|
||
# 不透明 refresh token 有效期(Go duration,如 720h = 30 天);access token 固定 24h。
|
||
AUTH_REFRESH_TTL=720h
|
||
# refresh token 单次使用轮换默认开启(用旧换新、防重放);仅当客户端无法保存轮换后的
|
||
# 新 token 时才设为 true 关闭轮换。
|
||
AUTH_REFRESH_ROTATE_DISABLED=false
|
||
|
||
# ---- 数据库 ----
|
||
# SQLite 为默认(单二进制、无需外部服务)。
|
||
DB_SQLITE_PATH=./data/cyrene.db
|
||
# PostgreSQL + pgvector 为可选增强;未配置时走 SQLite。相关向量能力在 M4 接入。
|
||
# DB_PG_URL=postgres://cyrene:cyrene_pass@localhost:5432/cyrene_ai?sslmode=disable
|
||
|
||
# ---- LLM 多供应商(LLM_PROVIDER 显式声明协议:openai / anthropic,默认 openai) ----
|
||
# ⚠️ 本节是【兜底】:管理面板「LLM 模型」页保存会写入本地 models.json(默认 <DATA_DIR>/models.json,已 gitignore),
|
||
# 只要 models.json 存在且有效,运行中的 LLM 就优先用它的多厂商多模型组,并支持面板实时保存→热更新(无需重启)。
|
||
# 仅当 models.json 不存在/无效时才回退到下面的 .env。
|
||
# Provider = openai:OpenAI 兼容 /chat/completions(含 OpenAI 兼容网关,也可经它承载 Anthropic 模型,但失去原生 tool input 对象优势)
|
||
LLM_PROVIDER=openai
|
||
|
||
LLM_BASE_URL=https://api.openai.com/v1
|
||
LLM_API_KEY=sk-xxxxx
|
||
LLM_MODEL=gpt-4o
|
||
LLM_FALLBACK_MODEL=gpt-4o-mini
|
||
# 最后一道回退模型(fallback 链末端)的 token 预算上限。仅当链确有回退模型、
|
||
# 且该模型组未在 models.json 设 maxTokens、请求也未显式给 MaxTokens 时生效;
|
||
# 0 = 关闭该兜底(改用适配器默认,如 anthropic 8192)。每模型组预算见 models.json 的 maxTokens。
|
||
LLM_FALLBACK_MAX_TOKENS=8192
|
||
# 推理开关的【提供商形状】声明(裁决 03.4.2 / 08.4.1):auto(默认,= 留空)/ deepseek /
|
||
# openai / vllm / dashscope。形状决定把思考开关下发改成哪个字段(如 vllm =
|
||
# chat_template_kwargs.enable_thinking、dashscope = 顶层 enable_thinking),必须按端点真实形状
|
||
# 声明——发错形状会被上游拒。留空/auto = 按模型名与 base URL 推断厂商,形状有歧义时一个字段都不发。
|
||
# ⚠️ 本键只作用于 .env 合成的模型组:存在有效 models.json 时,以该组的 reasoning.kind 为准
|
||
# (面板可编辑,见「LLM 模型」页)。
|
||
LLM_REASONING_KIND=
|
||
|
||
# ---- LLM 视觉模型(视觉/OCR 工具用的模型;与「主模型能否收图」无关) ----
|
||
# 语义(v0.53 修正):主模型自己能不能收图,看 models.json 生效组的 multimodal 字段(面板可勾选),
|
||
# 不是看这里;本节的模型【只供 vision / ocr 工具】调用。都不配置时工具回落用主模型(LLM_MODEL)。
|
||
# LLM_VISION_MODEL=gpt-4o-mini
|
||
# OCR 工具单独用另一个模型(可选):留空 = 复用 LLM_VISION_MODEL。
|
||
# LLM_OCR_MODEL=qwen-vl-ocr
|
||
|
||
# Provider = anthropic:Anthropic Messages /v1/messages(tool_use.input 为结构化对象,工具循环更稳)
|
||
# ANTHROPIC_BASE_URL=https://api.anthropic.com
|
||
# ANTHROPIC_API_KEY=sk-ant-xxxxx
|
||
# ANTHROPIC_MODEL=claude-sonnet-4-20250514
|
||
# ANTHROPIC_FALLBACK_MODEL=claude-haiku-3-5
|
||
# ⚠️ 若 ANTHROPIC_BASE_URL 指向 DeepSeek(https://api.deepseek.com/anthropic),模型名须用 DeepSeek 当前名称
|
||
# (deepseek-flash / deepseek-v4-pro):不认识的名称(如 claude-*)会被服务端【静默映射成 deepseek-flash】,
|
||
# 配置错了不会报错。旧的 deepseek-chat / deepseek-reasoner 已于 2026-07-24 停用。
|
||
|
||
# ---- LLM 本地第三级(降级链末端;默认关,裁决 03.4.3) ----
|
||
# 降级链为「主 → 备 → 本地」;本地这一级默认关闭(当前设备跑本地模型困难),链保持两级。
|
||
# 开启需要三个条件同时满足:LLM_LOCAL_ENABLED=true + LLM_LOCAL_BASE_URL + LLM_LOCAL_MODEL;
|
||
# 只开开关不配端点/模型会被记 WARN 并跳过(不会半配成一个只会失败的链尾步)。
|
||
LLM_LOCAL_ENABLED=false
|
||
# 本地端点协议:openai(llama.cpp / ollama / vLLM 兼容)或 anthropic;留空 = openai。
|
||
# LLM_LOCAL_PROVIDER=openai
|
||
# LLM_LOCAL_BASE_URL=http://127.0.0.1:8080/v1
|
||
# 本地服务通常不需要 key;留空即可。
|
||
# LLM_LOCAL_API_KEY=
|
||
# LLM_LOCAL_MODEL=qwen3-4b-instruct
|
||
|
||
# ---- 记忆嵌入(可选,真语义) ----
|
||
# 不配置时使用内置 n-gram / FTS 向量(dim=256)。配置后必须真实走语义路径。
|
||
# EMBEDDING_API_URL 是【完整 /embeddings 端点】(不是 base)——例:Ollama / llama.cpp = http://localhost:11434/v1/embeddings
|
||
# EMBEDDING_API_URL=http://localhost:11434/v1/embeddings
|
||
# EMBEDDING_API_KEY=
|
||
# EMBEDDING_MODEL=Qwen3-Embedding-0.6B # 推荐(Q8_0 ~639MB、dim=1024、ModelScope 国内可下)
|
||
|
||
# ---- IoT 设备提供者 ----
|
||
# mock = 模拟智能家居设备(开发测试用);none = 禁用 IoT。
|
||
IOT_PROVIDER=mock
|
||
|
||
# ---- 语音服务 ----
|
||
TTS_PROVIDER=edge-tts
|
||
STT_PROVIDER=dashscope
|
||
# DASHSCOPE_API_KEY=sk-xxxxx # ⚠️ 必填才能接通阿里百炼语音;未填时走降级链 (silent)。绝不打日志。
|
||
# --- 阿里百炼 DashScope 语音(STT + TTS 主链路)---
|
||
# DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/api/v1
|
||
# VOICE_STT_MODEL=qwen-audio-3.0-asr-flash
|
||
# VOICE_STT_LANGUAGE=zh
|
||
# 已实测:cosyvoice-v3.5-plus / cosyvoice-v2 走 HTTP SpeechSynthesizer 会回 418(引擎拒绝);
|
||
# 可用组合为 cosyvoice-v3-flash + 对应 v3 音色(longxiaochun_v3 龙小淳·女助手等)。
|
||
# 各模型音色不可混用(v2 名如 longxiaochun 用于 v3 模型会 418)。
|
||
# VOICE_TTS_MODEL=cosyvoice-v3-flash
|
||
# VOICE_TTS_VOICE_ID=longxiaochun_v3
|
||
# VOICE_TTS_FORMAT=wav
|
||
# VOICE_TTS_SAMPLE_RATE=24000
|
||
# 情绪/语气指令(TTS instruction):只对「复刻/设计音色」生效(可任意指令,如
|
||
# "语气开朗俏皮,像女朋友撒娇"),系统音色 longxiaochun_v3 必须用固定格式故不传。
|
||
# 长度≤100 字符(汉字记 2)。也可在 POST /api/v1/audio/speech 用 instruction 按请求覆盖。
|
||
# VOICE_TTS_INSTRUCTION=语气开朗俏皮,像女朋友撒娇
|
||
# 声音复刻前缀(create_voice 的 prefix,≤10 字母/数字,空则用 cyrene)。target_model
|
||
# 固定为 VOICE_TTS_MODEL(须与合成模型一致)。
|
||
# VOICE_CLONE_PREFIX=cyrene
|
||
# 声音复刻(响昔涟音色):先用参考音频(公网 URL)调 POST /api/v1/audio/voice-clone
|
||
# 建自定义音色,再把返回的 voice_id 填到 VOICE_TTS_VOICE_ID。
|
||
# ⚠️ 建音色必须公网可访问的参考音频 URL(create_voice 只收 input.url,不收 base64);
|
||
# 待主人提供参考音频公网 URL 方能真建音色。
|
||
|
||
# ---- 后台思考 ----
|
||
ENABLE_BACKGROUND_THINKING=true
|
||
# 自主思考心跳周期(秒)。默认 900(15 分钟一次);数值越小越频繁打扰。
|
||
THINK_INTERVAL_SEC=900
|
||
THINK_SILENCE_TIMEOUT_SEC=120
|
||
# 主动推送频率(design/12 §6):窗口内最多 PushLimit 次;推后冷却 Cooldown 秒;
|
||
# 同一风味(问候/提醒/分享/关心)在 KindWindow 秒内最多一次;主人最近消息在
|
||
# RecentChatCooldown 秒内则冷避不推。收敛默认值:1 次 / 60 分钟 + 推后 30 分钟冷却。
|
||
THINK_PUSH_LIMIT=1
|
||
THINK_PUSH_WINDOW_SEC=3600
|
||
THINK_PUSH_COOLDOWN_SEC=1800
|
||
THINK_RECENT_CHAT_COOLDOWN_SEC=600
|
||
THINK_KIND_WINDOW_SEC=7200
|
||
# 安静时段(本地时钟小时,默认 23:00-07:00;两端相等且非 0 则关闭)。
|
||
# 同时用于 backthink 后台思考与 channelbridge 公共平台安静时段轻思考(design/12 §6 策略五)。
|
||
QUIET_START_HOUR=23
|
||
QUIET_END_HOUR=7
|
||
|
||
# ---- 唤醒式能力渐进(capacity 意图判定,design/14 §2.2) ----
|
||
# L3 = 模型辅助的意图分类:仅当 L1 启发式与 L2 上下文仍拿不准时介入一次轻量模型调用。
|
||
# 默认关闭(纯启发式够日常,且该层要多花一次模型调用);关闭时该层从不运行,
|
||
# L1/L2/L4 的行为与接线前逐字节一致。
|
||
CAPACITY_L3_ENABLED=false
|
||
# L3 判定结果的缓存 TTL(Go duration,如 5m):同一段回合文本在此窗口内复用判定,避免每轮都问模型;
|
||
# 留空 = 5m;0 或解析不出 = 不缓存。
|
||
CAPACITY_L3_CACHE_TTL=5m
|
||
|
||
# ---- 子代理(orchestration,design/05 §7) ----
|
||
# 单个子代理整次运行的时限(秒)。默认 600 = 10 分钟(裁决 02.4.4:agent_timeout
|
||
# 可配置);模型派发时可用 subagent_spawn 的 timeout_seconds 参数按调用覆盖。
|
||
SUBAGENT_TIMEOUT_SEC=600
|
||
|
||
# ---- 护栏与上下文预算(design/04 §1.3 / §5) ----
|
||
# 上下文溢出压缩预算(token,离线估算值)。默认启用:会话估算上下文超过它时,
|
||
# 更早的轮次被摘要成一条前导摘要消息,近期尾部(含尾部工具结果)原样保留。
|
||
# 默认 32768 = loop.DefaultMaxContextTokens:默认模型(gpt-4o)窗口 128K,
|
||
# 它只占四分之一,给系统提示词/工具 schema/本轮输出留足余量,且远高于日常对话
|
||
# 体量(正常聊天几乎不触发压缩)。设 0(或负数)= 关闭压缩,行为与接线前一致。
|
||
CONTEXT_MAX_TOKENS=32768
|
||
# 内容策略关键词表(逗号分隔,大小写不敏感的子串匹配)。留空 = 不挂关键词护栏
|
||
# (项目不内置任何词表,只有你显式声明过的词才会被拦)。敏感信息(API key /
|
||
# bearer token / 密码 / 私钥)为阻断档、请求与响应各有长度上限,这两项是代码
|
||
# 内定的安全默认值,不对外开放配置(见 cmd/cyrene/wire_guardrail.go)。
|
||
# GUARDRAIL_KEYWORDS=
|
||
|
||
# ---- 主人身份说明书注入范围(design/11 §0 红线) ----
|
||
# 主人身份说明书(owner.yaml identityFile)注入范围:owner_only(默认,仅主人会话) | always(所有会话,含群聊/陌生人,仅自测) | off。
|
||
# owner_only 按渠道层强类型 actor 元数据判定;非法值回退 owner_only 并记 WARN(绝不静默放行)。
|
||
# 它只决定那段知识进不进该会话的上下文,不参与任何身份/权限判定(身份始终看 actor 元数据 + 白名单)。
|
||
OWNER_IDENTITY_INJECTION=owner_only
|
||
|
||
# ---- 推送出口(D1,主动推送的两级投递)----
|
||
# 主动消息在 WS/IM 投递之外,异步镜像到「主人自建统一推送服务」(主通道)。
|
||
# 该服务不可达/未配时,日志注明「个推(Getui)回退待接入」——当前无 Getui SDK,不伪造投递。
|
||
# 填写自建服务的 webhook 地址并置 ENABLE=true 即启用;token 只走 Authorization 头,不落日志。
|
||
PUSH_EXPORTER_ENABLED=false
|
||
# PUSH_EXPORTER_URL=https://push.example.com/webhook
|
||
# PUSH_EXPORTER_TOKEN=change-me
|
||
# PUSH_EXPORTER_TIMEOUT_SEC=5
|
||
# 个推(Getui)回退字段:预留占位,SDK 未接入,当前不生效。
|
||
# GETUI_APP_ID=
|
||
# GETUI_APP_KEY=
|
||
# GETUI_MASTER_SECRET=
|
||
# GETUI_BASE_URL=
|
||
|
||
# ---- WebSocket ----
|
||
WS_MAX_CONNECTIONS=1000
|
||
SESSION_IDLE_TIMEOUT_MIN=30
|
||
|
||
# ---- MCP 服务器(可选,JSON 数组字符串;每台 server 含 name/command/args/url/enabled) ----
|
||
# stdio 子进程示例:
|
||
# MCP_SERVERS_JSON=[{"name":"calc","command":"mcp-calc","args":["--stdio"],"enabled":true}]
|
||
# SSE 端点示例:
|
||
# MCP_SERVERS_JSON=[{"name":"weather","url":"http://localhost:3001/sse","enabled":true}]
|
||
|
||
# ---- 本地执行沙箱(exec/terminal 工具;默认关闭,授权放权) ----
|
||
# 只有 Enabled=true 时 agent 才可执行命令;仍需命令白名单与根目录边界。
|
||
# EXEC_SANDBOX_ENABLED=false
|
||
# EXEC_SANDBOX_COMMANDS=git,ls,cat,pwd
|
||
# EXEC_SANDBOX_ROOTS=./data
|
||
# EXEC_SANDBOX_ENV=PATH
|
||
|
||
# ---- 跨域白名单 ----
|
||
ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000
|
||
|
||
# ---- KOOK(KaiHeiLa)渠道 ----
|
||
# 单账号走环境变量;多账号走下方 CHANNELS_JSON。
|
||
# .env 仅提供【必要连接兜底】;接收模式 / webhook 回调路由 / verify_token / encrypt_key 等
|
||
# 业务·高级项一律在管理面板「渠道管理」配置(写入 channels.json,热更新),不落 .env。
|
||
# CHANNEL_KOOK_TOKEN 为 KOOK 开发者中心机器人 token(敏感,勿写日志/提交)。
|
||
# CHANNEL_KOOK_BASE_URL 可选,默认 https://www.kookapp.cn/api/v3。
|
||
# CHANNEL_KOOK_TOKEN=
|
||
# CHANNEL_KOOK_BASE_URL=
|
||
|
||
# ---- IM 多账号 / 黑白名单(可选,design/16 §4.6 §5-6) ----
|
||
# ⚠️ 本节是【兜底】:管理面板「渠道管理」页保存会写入本地 channels.json(默认 <DATA_DIR>/channels.json,已 gitignore),
|
||
# 只要 channels.json 存在且有效,运行中的渠道 adapter 就优先用它的多平台账号配置,并支持面板实时保存→热更新(无需重启)。
|
||
# 仅当 channels.json 不存在/无效时才回退到下面的 CHANNELS_JSON 与 CHANNEL_<NAME>_*。
|
||
# 业务·高级项(接收模式 receive_mode / webhook 回调路由与 verify_token、encrypt_key / 黑白名单 / 限流)
|
||
# 一律在管理面板「渠道管理」配置:写 channels.json、热更新;.env 仅作无文件时的必要连接回退(token/base_url 等)。
|
||
# 单账号仍走上面 CHANNEL_<NAME>_* 环境变量;这里提供独立的 JSON 注册表,
|
||
# 支持同一平台配多个接入配置(多账号),并配群聊/私聊黑白名单(代码层拦截,
|
||
# 被拉黑/不在白名单的群或用户消息不进 LLM,且有审计)。形如:
|
||
# CHANNELS_JSON={"telegram":[{"id":"conf0","config":{"bot_token":"..."},"denyUsers":["12345"],"denyGroups":["-100"]}]}
|
||
# 每个 account 字段:id(平台内唯一)、config(平台特有凭据 map)、
|
||
# allowGroups/denyGroups(群黑白名单,allowGroups 非空则成为白名单)、
|
||
# allowUsers/denyUsers(私聊用户黑白名单)。未配置时按单账号 env 路径处理。
|
||
# 群/总限流与总上限(可选,design/12 §6 策略三/四,公共平台防刷屏/最小化打扰):
|
||
# groupMsgPerMin 群聊每分钟上限(0=用默认6,-1=不限,正整数=该值)
|
||
# msgPerMin 非主人消息每分钟总上限(>0 生效,0/-1=不限)
|
||
# maxMessages 待处理上限,接近上限时由审查模型剔除低价值消息(0=用默认50,-1=不限,正整数=该值)
|
||
# 旧账号不配这些字段默认走「保护性默认/不限」,保持向后兼容。
|
||
# CHANNELS_JSON=
|