4 Commits

Author SHA1 Message Date
zheromiku 6307013085 Merge pull request 'revert(docs): 移除 AGENTS.md —— 改为只在 knowledge-governance 试点' (#2) from revert/agents-pointer into main
Build and Push Docker Image / build-ui (push) Has been cancelled
Build and Push Docker Image / build-docreader (push) Has been cancelled
Build and Push Docker Image / build-sandbox (push) Has been cancelled
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Image / merge (push) Has been cancelled
2026-10-10 14:58:55 +08:00
姚章浩 87df5751b7 revert(docs): 移除 AGENTS.md —— 改为只在 knowledge-governance 试点
按指示先把范围收回到单个仓做实验:本仓恢复到加 AGENTS.md 之前的状态,
等试点验收通过再统一铺开。

本提交只删文件,不改任何代码。
2026-10-10 14:58:52 +08:00
zheromiku e19ad4276c Merge pull request 'docs(agents): 加 AGENTS.md 操作手册与规范指针' (#1) from docs/agents-pointer into main
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Image / merge (push) Has been cancelled
Build and Push Docker Image / build-ui (push) Has been cancelled
Build and Push Docker Image / build-docreader (push) Has been cancelled
Build and Push Docker Image / build-sandbox (push) Has been cancelled
2026-10-10 14:54:32 +08:00
姚章浩 f5f842b46a docs(agents): 加 AGENTS.md 操作手册与规范指针
本仓此前没有任何 agent 上下文文件,代理每次都得重新讲一遍规范。
新增 AGENTS.md:指向系统级规范(zheromiku/eng-standards-main),并写明
本仓已核实的现状(CI / runner / main 已受分支保护)。

为什么用 AGENTS.md 而不是 .hermes.md:Codex / Claude Code / OpenCode 读的
也是 AGENTS.md,跨工具可移植。
2026-10-10 14:52:18 +08:00
4 changed files with 2 additions and 186 deletions
-9
View File
@@ -210,15 +210,6 @@ DB_PASSWORD=postgres123!@#
# 数据库名称
DB_NAME=WeKnora
# PostgreSQL 全局最大连接数(Compose 内置 PostgreSQL 服务)
POSTGRES_MAX_CONNECTIONS=300
# WeKnora database/sql 连接池
DB_MAX_OPEN_CONNS=120
DB_MAX_IDLE_CONNS=20
DB_CONN_MAX_IDLE_TIME=5m
DB_CONN_MAX_LIFETIME=10m
# 如果使用 redis 作为流处理后端,需要配置以下参数
# Redis用户名,Redis 6.0+ ACL 功能支持(可选)
# REDIS_USERNAME=
-5
View File
@@ -79,10 +79,6 @@ services:
- DB_USER=${DB_USER:-}
- DB_PASSWORD=${DB_PASSWORD:-}
- DB_NAME=${DB_NAME:-}
- DB_MAX_OPEN_CONNS=${DB_MAX_OPEN_CONNS:-120}
- DB_MAX_IDLE_CONNS=${DB_MAX_IDLE_CONNS:-20}
- DB_CONN_MAX_IDLE_TIME=${DB_CONN_MAX_IDLE_TIME:-5m}
- DB_CONN_MAX_LIFETIME=${DB_CONN_MAX_LIFETIME:-10m}
- TZ=${TZ:-Asia/Shanghai}
- WEKNORA_LANGUAGE=${WEKNORA_LANGUAGE:-zh-CN}
# ========== Langfuse (optional observability) ==========
@@ -295,7 +291,6 @@ services:
postgres:
image: paradedb/paradedb:v0.22.2-pg17
container_name: WeKnora-postgres
command: ["postgres", "-c", "max_connections=${POSTGRES_MAX_CONNECTIONS:-300}"]
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
+2 -67
View File
@@ -90,62 +90,6 @@ import (
wgrpc "github.com/weaviate/weaviate-go-client/v5/weaviate/grpc"
)
func nonNegativeEnvInt(name string, fallback int) int {
raw := strings.TrimSpace(os.Getenv(name))
if raw == "" {
return fallback
}
value, err := strconv.Atoi(raw)
if err != nil || value < 0 {
return fallback
}
return value
}
func nonNegativeEnvDuration(name string, fallback time.Duration) time.Duration {
raw := strings.TrimSpace(os.Getenv(name))
if raw == "" {
return fallback
}
if raw == "0" {
return 0
}
value, err := time.ParseDuration(raw)
if err != nil || value < 0 {
return fallback
}
return value
}
type databasePoolConfig struct {
maxOpen int
maxIdle int
maxIdleTime time.Duration
maxLifetime time.Duration
}
func databasePoolConfigFromEnv() databasePoolConfig {
cfg := databasePoolConfig{
maxOpen: nonNegativeEnvInt("DB_MAX_OPEN_CONNS", 0),
maxIdle: nonNegativeEnvInt("DB_MAX_IDLE_CONNS", 10),
maxIdleTime: nonNegativeEnvDuration("DB_CONN_MAX_IDLE_TIME", 0),
maxLifetime: nonNegativeEnvDuration("DB_CONN_MAX_LIFETIME", 10*time.Minute),
}
if cfg.maxOpen > 0 && cfg.maxIdle > cfg.maxOpen {
cfg.maxIdle = cfg.maxOpen
}
return cfg
}
func applyDatabasePoolConfig(db *sql.DB, cfg databasePoolConfig) {
db.SetMaxOpenConns(cfg.maxOpen)
db.SetMaxIdleConns(cfg.maxIdle)
db.SetConnMaxIdleTime(cfg.maxIdleTime)
db.SetConnMaxLifetime(cfg.maxLifetime)
}
// BuildContainer constructs the dependency injection container
// Registers all components, services, repositories and handlers needed by the application
// Creates a fully configured application container with proper dependency resolution
@@ -664,19 +608,10 @@ func initDatabase(cfg *config.Config) (*gorm.DB, error) {
// Limiting to a single open connection serialises all DB access and
// prevents "database is locked" errors from concurrent goroutines.
sqlDB.SetMaxOpenConns(1)
sqlDB.SetConnMaxLifetime(10 * time.Minute)
} else {
poolCfg := databasePoolConfigFromEnv()
applyDatabasePoolConfig(sqlDB, poolCfg)
logger.Infof(
context.Background(),
"Database pool configured: max_open=%d max_idle=%d max_idle_time=%s max_lifetime=%s",
poolCfg.maxOpen,
poolCfg.maxIdle,
poolCfg.maxIdleTime,
poolCfg.maxLifetime,
)
sqlDB.SetMaxIdleConns(10)
}
sqlDB.SetConnMaxLifetime(time.Duration(10) * time.Minute)
return db, nil
}
-105
View File
@@ -1,105 +0,0 @@
package container
import (
"database/sql"
"testing"
"time"
)
func TestNonNegativeEnvInt(t *testing.T) {
tests := []struct {
name string
raw string
fallback int
want int
}{
{name: "uses fallback when unset", raw: "", fallback: 10, want: 10},
{name: "accepts positive value", raw: "120", fallback: 10, want: 120},
{name: "accepts zero", raw: "0", fallback: 10, want: 0},
{name: "rejects negative value", raw: "-1", fallback: 10, want: 10},
{name: "rejects invalid value", raw: "many", fallback: 10, want: 10},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_DB_POOL_INT", tt.raw)
if got := nonNegativeEnvInt("TEST_DB_POOL_INT", tt.fallback); got != tt.want {
t.Fatalf("nonNegativeEnvInt() = %d, want %d", got, tt.want)
}
})
}
}
func TestNonNegativeEnvDuration(t *testing.T) {
tests := []struct {
name string
raw string
fallback time.Duration
want time.Duration
}{
{name: "uses fallback when unset", raw: "", fallback: 10 * time.Minute, want: 10 * time.Minute},
{name: "accepts duration", raw: "5m", fallback: 10 * time.Minute, want: 5 * time.Minute},
{name: "accepts zero", raw: "0", fallback: 10 * time.Minute, want: 0},
{name: "rejects negative duration", raw: "-1m", fallback: 10 * time.Minute, want: 10 * time.Minute},
{name: "rejects invalid duration", raw: "later", fallback: 10 * time.Minute, want: 10 * time.Minute},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("TEST_DB_POOL_DURATION", tt.raw)
if got := nonNegativeEnvDuration("TEST_DB_POOL_DURATION", tt.fallback); got != tt.want {
t.Fatalf("nonNegativeEnvDuration() = %s, want %s", got, tt.want)
}
})
}
}
func TestDatabasePoolConfigFromEnv(t *testing.T) {
t.Setenv("DB_MAX_OPEN_CONNS", "120")
t.Setenv("DB_MAX_IDLE_CONNS", "20")
t.Setenv("DB_CONN_MAX_IDLE_TIME", "5m")
t.Setenv("DB_CONN_MAX_LIFETIME", "10m")
got := databasePoolConfigFromEnv()
if got.maxOpen != 120 {
t.Fatalf("maxOpen = %d, want 120", got.maxOpen)
}
if got.maxIdle != 20 {
t.Fatalf("maxIdle = %d, want 20", got.maxIdle)
}
if got.maxIdleTime != 5*time.Minute {
t.Fatalf("maxIdleTime = %s, want 5m", got.maxIdleTime)
}
if got.maxLifetime != 10*time.Minute {
t.Fatalf("maxLifetime = %s, want 10m", got.maxLifetime)
}
}
func TestDatabasePoolConfigClampsIdleToOpen(t *testing.T) {
t.Setenv("DB_MAX_OPEN_CONNS", "5")
t.Setenv("DB_MAX_IDLE_CONNS", "20")
got := databasePoolConfigFromEnv()
if got.maxIdle != 5 {
t.Fatalf("maxIdle = %d, want 5", got.maxIdle)
}
}
func TestApplyDatabasePoolConfig(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatalf("sql.Open() error = %v", err)
}
defer db.Close()
applyDatabasePoolConfig(db, databasePoolConfig{
maxOpen: 120,
maxIdle: 20,
maxIdleTime: 5 * time.Minute,
maxLifetime: 10 * time.Minute,
})
if got := db.Stats().MaxOpenConnections; got != 120 {
t.Fatalf("MaxOpenConnections = %d, want 120", got)
}
}