From 018fe07773fd23bf0d7c9b32759e7f78c70ffbc3 Mon Sep 17 00:00:00 2001 From: hhs <386998068@qq.com> Date: Tue, 9 Jun 2026 23:53:08 +0800 Subject: [PATCH] =?UTF-8?q?chore(init):=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84=E4=B8=8E?= =?UTF-8?q?=20Go=20=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 7 ++ .gitea/workflows/go-loom.yaml | 113 +++++++++++++++++++++++++++++++++ .gitignore | 1 + CLAUDE.md | 111 ++++++++++++++++++++++++++++++++ cmd/server/main.go | 1 + configs/application.yaml | 14 ++++ go.mod | 3 + internal/config/application.go | 1 + internal/config/loader.go | 1 + internal/handler/handler.go | 1 + internal/llm/chatmodel.go | 1 + internal/llm/client.go | 1 + internal/model/config.go | 1 + internal/model/types.go | 1 + internal/service/agent.go | 1 + internal/service/assembler.go | 1 + internal/service/chat.go | 1 + internal/service/runner.go | 1 + pkg/types/codes.go | 1 + pkg/types/errors.go | 1 + 20 files changed, 263 insertions(+) create mode 100644 .env.example create mode 100644 .gitea/workflows/go-loom.yaml create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 cmd/server/main.go create mode 100644 configs/application.yaml create mode 100644 go.mod create mode 100644 internal/config/application.go create mode 100644 internal/config/loader.go create mode 100644 internal/handler/handler.go create mode 100644 internal/llm/chatmodel.go create mode 100644 internal/llm/client.go create mode 100644 internal/model/config.go create mode 100644 internal/model/types.go create mode 100644 internal/service/agent.go create mode 100644 internal/service/assembler.go create mode 100644 internal/service/chat.go create mode 100644 internal/service/runner.go create mode 100644 pkg/types/codes.go create mode 100644 pkg/types/errors.go diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f07b278 --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# LLM API 配置 +LLM_API_KEY=your-api-key-here +LLM_BASE_URL=https://api.deepseek.com +LLM_MODEL=deepseek-chat + +# 服务器配置 +SERVER_PORT=8091 diff --git a/.gitea/workflows/go-loom.yaml b/.gitea/workflows/go-loom.yaml new file mode 100644 index 0000000..3bfd6b8 --- /dev/null +++ b/.gitea/workflows/go-loom.yaml @@ -0,0 +1,113 @@ +name: GoLoom CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + GO_VERSION: '1.26' + GOLANGCI_LINT_VERSION: 'v1.57.2' + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Download dependencies + run: go mod download + + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v4 + with: + version: ${{ env.GOLANGCI_LINT_VERSION }} + args: --timeout=5m + + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Download dependencies + run: go mod download + + - name: Run tests + run: go test -v -race -coverprofile=coverage.out ./... + + - name: Upload coverage + if: success() + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage.out + + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, test] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Download dependencies + run: go mod download + + - name: Build binary + run: | + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ + go build -ldflags="-s -w" -o goloom-server ./cmd/server + + - name: Upload binary + uses: actions/upload-artifact@v4 + with: + name: goloom-server + path: goloom-server + + docker: + name: Docker Build + runs-on: ubuntu-latest + needs: [build] + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download binary + uses: actions/download-artifact@v4 + with: + name: goloom-server + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: false + tags: | + goloom:latest + goloom:${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96c0ecc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +docs/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5c0a7ea --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,111 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +GoLoom is an **AI Agent Scaffold** — a Go HTTP server for building and orchestrating multi-agent LLM workflows. It supports OpenAI-compatible APIs (DeepSeek, Tongyi Qianwen, etc.), four agent orchestration patterns (LLM, Sequential, Parallel, Loop), synchronous and SSE streaming chat, and tool calling via OpenAI function calling. A Next.js frontend is documented but not yet committed. + +**Module name:** `ai-agent-scaffold-go` +**Language:** Go 1.26 +**Documentation language:** Chinese (docs/ directory) + +## Build and Run + +```bash +# First-time setup +go mod init ai-agent-scaffold-go +go mod tidy + +# Build +go build ./... + +# Run (requires .env and configs/application.yaml — see docs/build-from-scratch.md) +go run ./cmd/server + +# Dependencies +go get github.com/gin-gonic/gin +go get go.uber.org/zap +go get gopkg.in/yaml.v3 +go get github.com/joho/godotenv +``` + +No Makefile, test suite, or linting configuration exists yet. The CI file at `.gitea/workflows/go-loom.yaml` is a placeholder. + +## Architecture + +**Three-layer design: Handler → Service → Model/LLM** + +``` +cmd/server/main.go — Entry point: .env → config → bootstrap → Gin server +internal/handler/handler.go — Presentation: Gin routes, request/response, SSE +internal/service/ — Business: ChatService, Agent impls, Runner, Assembler +internal/model/ — Domain: config structs, core interfaces (Agent, ChatModel, Tool, Runner) +internal/config/ — Config loading: YAML parsing + ${VAR} env expansion +internal/llm/ — OpenAI-compatible HTTP client + ChatModel adapter +pkg/types/ — Error codes (codes.go) and AppError type (errors.go) +configs/ — application.yaml + agent/*.yaml definitions +``` + +**Dependency direction:** handler → service → model/llm. `model` imports nothing internal. + +## Core Interfaces (internal/model/types.go) + +- **Tool** — `Name()`, `Description()`, `Call(ctx, input string) (string, error)`. Uses single `query` parameter. +- **ChatModel** — `Generate()` (sync) and `Stream()` (async via channels). Holds tool list for function calling. +- **Agent** — `Name()`, `Run(ctx, ChatContent) (string, error)`, `Stream(ctx, ChatContent, chan<- string) error` +- **Runner** — session ID generation + delegates to Agent for sync/stream execution + +## Agent Types (internal/service/agent.go) + +1. **LLMAgent** — single LLM call with tool-call loop (max 4 rounds) +2. **SequentialAgent** — runs sub-agents in order; output injected via `{outputKey}` template vars +3. **ParallelAgent** — runs all sub-agents concurrently, concatenates results +4. **LoopAgent** — repeats sub-agents up to `maxIterations` times + +## Configuration System + +Three-layer config: `.env` (secrets) → `configs/application.yaml` (server settings) → `configs/agent/*.yaml` (agent definitions). Agent YAML supports `${VAR}` and `${VAR:-default}` env var expansion at load time. + +## HTTP API (base path /api/v1, default port 8091) + +| Method | Path | Purpose | +|--------|------|---------| +| GET | `/healthz` | Health check (no envelope) | +| GET | `/api/v1/query_ai_agent_config_list` | List registered agents | +| POST | `/api/v1/create_session` | Create session (JSON body) | +| GET | `/api/v1/create_session` | Create session (query params) | +| POST | `/api/v1/chat` | Synchronous chat | +| POST | `/api/v1/chat_stream` | SSE streaming chat | + +Unified response envelope: `{ "code": "0000", "info": "success", "data": {} }` + +Typical flow: list agents → create session → chat with sessionId. + +## Key Design Notes + +- LLM client is hand-rolled HTTP (not an SDK) — OpenAI-compatible endpoints only +- Tool calling uses single `query` parameter model, not arbitrary function signatures +- In-memory storage (sync.RWMutex + Map) for agent registry and sessions +- SSE streaming uses goroutine + channel pattern +- Assembler (`internal/service/assembler.go`) reads YAML configs and wires up the full agent/runner/chatmodel chain in one function + +## Development Conventions + +- **Git 提交粒度**:每完成一个功能函数即 commit 一次;接口与结构体等定义可完成一个整体部分后再提交 +- **提交格式**:`(): ` + - type:`feat` / `fix` / `refactor` / `docs` / `style` / `test` / `chore` + - scope:模块名(如 `config`、`llm`、`agent`、`handler`、`service`、`types`) + - description:中文或英文简述 + - 示例:`feat(config): 实现 YAML 配置加载与环境变量展开`、`feat(llm): 添加 OpenAI 兼容 HTTP 客户端` +- **进度追踪**:每进入下一个功能代码块前,检查 `docs/plan.md` 中的完成情况;每完成一个功能,将对应条目在 plan.md 中标记为已完成 + +## Documentation + +All detailed docs are in `docs/` (Chinese): +- `docs/architecture.md` — architecture design and design decisions +- `docs/api-reference.md` — HTTP API spec with curl examples +- `docs/build-from-scratch.md` — complete Go backend source code and build guide +- `docs/frontend-build-from-scratch.md` — complete Next.js frontend source code +- `docs/testing-guide.md` — testing conventions (standard `testing` + optional `testify`, no external mock frameworks) +- `docs/logging-guide.md` — zap logging levels, required log points, and structured field conventions diff --git a/cmd/server/main.go b/cmd/server/main.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/cmd/server/main.go @@ -0,0 +1 @@ +package main diff --git a/configs/application.yaml b/configs/application.yaml new file mode 100644 index 0000000..b97f070 --- /dev/null +++ b/configs/application.yaml @@ -0,0 +1,14 @@ +app: + name: goloom + env: development + port: ${SERVER_PORT:-8091} + +llm: + base_url: ${LLM_BASE_URL} + api_key: ${LLM_API_KEY} + model: ${LLM_MODEL:-deepseek-chat} + timeout: 30s + max_retries: 3 + +agent: + config_dir: configs/agent diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..975bea2 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module ai-agent-scaffold-go + +go 1.26.2 diff --git a/internal/config/application.go b/internal/config/application.go new file mode 100644 index 0000000..d912156 --- /dev/null +++ b/internal/config/application.go @@ -0,0 +1 @@ +package config diff --git a/internal/config/loader.go b/internal/config/loader.go new file mode 100644 index 0000000..d912156 --- /dev/null +++ b/internal/config/loader.go @@ -0,0 +1 @@ +package config diff --git a/internal/handler/handler.go b/internal/handler/handler.go new file mode 100644 index 0000000..abeebd1 --- /dev/null +++ b/internal/handler/handler.go @@ -0,0 +1 @@ +package handler diff --git a/internal/llm/chatmodel.go b/internal/llm/chatmodel.go new file mode 100644 index 0000000..006c3de --- /dev/null +++ b/internal/llm/chatmodel.go @@ -0,0 +1 @@ +package llm diff --git a/internal/llm/client.go b/internal/llm/client.go new file mode 100644 index 0000000..006c3de --- /dev/null +++ b/internal/llm/client.go @@ -0,0 +1 @@ +package llm diff --git a/internal/model/config.go b/internal/model/config.go new file mode 100644 index 0000000..8b53790 --- /dev/null +++ b/internal/model/config.go @@ -0,0 +1 @@ +package model diff --git a/internal/model/types.go b/internal/model/types.go new file mode 100644 index 0000000..8b53790 --- /dev/null +++ b/internal/model/types.go @@ -0,0 +1 @@ +package model diff --git a/internal/service/agent.go b/internal/service/agent.go new file mode 100644 index 0000000..6d43c33 --- /dev/null +++ b/internal/service/agent.go @@ -0,0 +1 @@ +package service diff --git a/internal/service/assembler.go b/internal/service/assembler.go new file mode 100644 index 0000000..6d43c33 --- /dev/null +++ b/internal/service/assembler.go @@ -0,0 +1 @@ +package service diff --git a/internal/service/chat.go b/internal/service/chat.go new file mode 100644 index 0000000..6d43c33 --- /dev/null +++ b/internal/service/chat.go @@ -0,0 +1 @@ +package service diff --git a/internal/service/runner.go b/internal/service/runner.go new file mode 100644 index 0000000..6d43c33 --- /dev/null +++ b/internal/service/runner.go @@ -0,0 +1 @@ +package service diff --git a/pkg/types/codes.go b/pkg/types/codes.go new file mode 100644 index 0000000..ab1254f --- /dev/null +++ b/pkg/types/codes.go @@ -0,0 +1 @@ +package types diff --git a/pkg/types/errors.go b/pkg/types/errors.go new file mode 100644 index 0000000..ab1254f --- /dev/null +++ b/pkg/types/errors.go @@ -0,0 +1 @@ +package types