Skip to content

Commit 45dc09d

Browse files
committed
chore: merge upstream CLIProxyAPI v6.9.22
2 parents 5775476 + 5ab9afa commit 45dc09d

67 files changed

Lines changed: 6887 additions & 950 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: agents-md-guard
2+
3+
on:
4+
pull_request_target:
5+
types:
6+
- opened
7+
- synchronize
8+
- reopened
9+
10+
permissions:
11+
contents: read
12+
issues: write
13+
pull-requests: write
14+
15+
jobs:
16+
close-when-agents-md-changed:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Detect AGENTS.md changes and close PR
20+
uses: actions/github-script@v7
21+
with:
22+
script: |
23+
const prNumber = context.payload.pull_request.number;
24+
const { owner, repo } = context.repo;
25+
26+
const files = await github.paginate(github.rest.pulls.listFiles, {
27+
owner,
28+
repo,
29+
pull_number: prNumber,
30+
per_page: 100,
31+
});
32+
33+
const touchesAgentsMd = (path) =>
34+
typeof path === "string" &&
35+
(path === "AGENTS.md" || path.endsWith("/AGENTS.md"));
36+
37+
const touched = files.filter(
38+
(f) => touchesAgentsMd(f.filename) || touchesAgentsMd(f.previous_filename),
39+
);
40+
41+
if (touched.length === 0) {
42+
core.info("No AGENTS.md changes detected.");
43+
return;
44+
}
45+
46+
const changedList = touched
47+
.map((f) =>
48+
f.previous_filename && f.previous_filename !== f.filename
49+
? `- ${f.previous_filename} -> ${f.filename}`
50+
: `- ${f.filename}`,
51+
)
52+
.join("\n");
53+
54+
const body = [
55+
"This repository does not allow modifying `AGENTS.md` in pull requests.",
56+
"",
57+
"Detected changes:",
58+
changedList,
59+
"",
60+
"Please revert these changes and open a new PR without touching `AGENTS.md`.",
61+
].join("\n");
62+
63+
try {
64+
await github.rest.issues.createComment({
65+
owner,
66+
repo,
67+
issue_number: prNumber,
68+
body,
69+
});
70+
} catch (error) {
71+
core.warning(`Failed to comment on PR #${prNumber}: ${error.message}`);
72+
}
73+
74+
await github.rest.pulls.update({
75+
owner,
76+
repo,
77+
pull_number: prNumber,
78+
state: "closed",
79+
});
80+
81+
core.setFailed("PR modifies AGENTS.md");
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: auto-retarget-main-pr-to-dev
2+
3+
on:
4+
pull_request_target:
5+
types:
6+
- opened
7+
- reopened
8+
- edited
9+
branches:
10+
- main
11+
12+
permissions:
13+
contents: read
14+
issues: write
15+
pull-requests: write
16+
17+
jobs:
18+
retarget:
19+
if: github.actor != 'github-actions[bot]'
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Retarget PR base to dev
23+
uses: actions/github-script@v7
24+
with:
25+
script: |
26+
const pr = context.payload.pull_request;
27+
const prNumber = pr.number;
28+
const { owner, repo } = context.repo;
29+
30+
const baseRef = pr.base?.ref;
31+
const headRef = pr.head?.ref;
32+
const desiredBase = "dev";
33+
34+
if (baseRef !== "main") {
35+
core.info(`PR #${prNumber} base is ${baseRef}; nothing to do.`);
36+
return;
37+
}
38+
39+
if (headRef === desiredBase) {
40+
core.info(`PR #${prNumber} is ${desiredBase} -> main; skipping retarget.`);
41+
return;
42+
}
43+
44+
core.info(`Retargeting PR #${prNumber} base from ${baseRef} to ${desiredBase}.`);
45+
46+
try {
47+
await github.rest.pulls.update({
48+
owner,
49+
repo,
50+
pull_number: prNumber,
51+
base: desiredBase,
52+
});
53+
} catch (error) {
54+
core.setFailed(`Failed to retarget PR #${prNumber} to ${desiredBase}: ${error.message}`);
55+
return;
56+
}
57+
58+
const body = [
59+
`This pull request targeted \`${baseRef}\`.`,
60+
"",
61+
`The base branch has been automatically changed to \`${desiredBase}\`.`,
62+
].join("\n");
63+
64+
try {
65+
await github.rest.issues.createComment({
66+
owner,
67+
repo,
68+
issue_number: prNumber,
69+
body,
70+
});
71+
} catch (error) {
72+
core.warning(`Failed to comment on PR #${prNumber}: ${error.message}`);
73+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ GEMINI.md
6464
.agents/*
6565
.opencode/*
6666
.idea/*
67+
.beads/*
6768
.bmad/*
6869
_bmad/*
6970
_bmad-output/*

.upstream-sync-sha

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
941334da79cc7c1b405eb5f332ca382e8dae8317
1+
5ab9afac83dd60b764bd214f16000ae80888e562

.upstream-sync-tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v6.9.18
1+
v6.9.22

AGENTS.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# AGENTS.md
2+
3+
Go 1.26+ proxy server providing OpenAI/Gemini/Claude/Codex compatible APIs with OAuth and round-robin load balancing.
4+
5+
## Repository
6+
- GitHub: https://github.com/router-for-me/CLIProxyAPI
7+
8+
## Commands
9+
```bash
10+
gofmt -w . # Format (required after Go changes)
11+
go build -o cli-proxy-api ./cmd/server # Build
12+
go run ./cmd/server # Run dev server
13+
go test ./... # Run all tests
14+
go test -v -run TestName ./path/to/pkg # Run single test
15+
go build -o test-output ./cmd/server && rm test-output # Verify compile (REQUIRED after changes)
16+
```
17+
- Common flags: `--config <path>`, `--tui`, `--standalone`, `--local-model`, `--no-browser`, `--oauth-callback-port <port>`
18+
19+
## Config
20+
- Default config: `config.yaml` (template: `config.example.yaml`)
21+
- `.env` is auto-loaded from the working directory
22+
- Auth material defaults under `auths/`
23+
- Storage backends: file-based default; optional Postgres/git/object store (`PGSTORE_*`, `GITSTORE_*`, `OBJECTSTORE_*`)
24+
25+
## Architecture
26+
- `cmd/server/` — Server entrypoint
27+
- `internal/api/` — Gin HTTP API (routes, middleware, modules)
28+
- `internal/api/modules/amp/` — Amp integration (Amp-style routes + reverse proxy)
29+
- `internal/thinking/` — Main thinking/reasoning pipeline. `ApplyThinking()` (apply.go) parses suffixes (`suffix.go`, suffix overrides body), normalizes config to canonical `ThinkingConfig` (`types.go`), normalizes and validates centrally (`validate.go`/`convert.go`), then applies provider-specific output via `ProviderApplier`. Do not break this "canonical representation → per-provider translation" architecture.
30+
- `internal/runtime/executor/` — Per-provider runtime executors (incl. Codex WebSocket)
31+
- `internal/translator/` — Provider protocol translators (and shared `common`)
32+
- `internal/registry/` — Model registry + remote updater (`StartModelsUpdater`); `--local-model` disables remote updates
33+
- `internal/store/` — Storage implementations and secret resolution
34+
- `internal/managementasset/` — Config snapshots and management assets
35+
- `internal/cache/` — Request signature caching
36+
- `internal/watcher/` — Config hot-reload and watchers
37+
- `internal/wsrelay/` — WebSocket relay sessions
38+
- `internal/usage/` — Usage and token accounting
39+
- `internal/tui/` — Bubbletea terminal UI (`--tui`, `--standalone`)
40+
- `sdk/cliproxy/` — Embeddable SDK entry (service/builder/watchers/pipeline)
41+
- `test/` — Cross-module integration tests
42+
43+
## Code Conventions
44+
- Keep changes small and simple (KISS)
45+
- Comments in English only
46+
- If editing code that already contains non-English comments, translate them to English (don’t add new non-English comments)
47+
- For user-visible strings, keep the existing language used in that file/area
48+
- New Markdown docs should be in English unless the file is explicitly language-specific (e.g. `README_CN.md`)
49+
- As a rule, do not make standalone changes to `internal/translator/`. You may modify it only as part of broader changes elsewhere.
50+
- If a task requires changing only `internal/translator/`, run `gh repo view --json viewerPermission -q .viewerPermission` to confirm you have `WRITE`, `MAINTAIN`, or `ADMIN`. If you do, you may proceed; otherwise, file a GitHub issue including the goal, rationale, and the intended implementation code, then stop further work.
51+
- `internal/runtime/executor/` should contain executors and their unit tests only. Place any helper/supporting files under `internal/runtime/executor/helps/`.
52+
- Follow `gofmt`; keep imports goimports-style; wrap errors with context where helpful
53+
- Do not use `log.Fatal`/`log.Fatalf` (terminates the process); prefer returning errors and logging via logrus
54+
- Shadowed variables: use method suffix (`errStart := server.Start()`)
55+
- Wrap defer errors: `defer func() { if err := f.Close(); err != nil { log.Errorf(...) } }()`
56+
- Use logrus structured logging; avoid leaking secrets/tokens in logs
57+
- Avoid panics in HTTP handlers; prefer logged errors and meaningful HTTP status codes
58+
- Timeouts are allowed only during credential acquisition; after an upstream connection is established, do not set timeouts for any subsequent network behavior. Intentional exceptions that must remain allowed are the Codex websocket liveness deadlines in `internal/runtime/executor/codex_websockets_executor.go`, the wsrelay session deadlines in `internal/wsrelay/session.go`, the management APICall timeout in `internal/api/handlers/management/api_tools.go`, and the `cmd/fetch_antigravity_models` utility timeouts

UPSTREAM_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v6.9.15
1+
v6.9.22

cmd/server/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ func main() {
312312
gitStoreRemoteURL string
313313
gitStoreUser string
314314
gitStorePassword string
315+
gitStoreBranch string
315316
gitStoreLocalPath string
316317
gitStoreInst *store.GitTokenStore
317318
gitStoreRoot string
@@ -381,6 +382,9 @@ func main() {
381382
if value, ok := lookupEnv("GITSTORE_LOCAL_PATH", "gitstore_local_path"); ok {
382383
gitStoreLocalPath = value
383384
}
385+
if value, ok := lookupEnv("GITSTORE_GIT_BRANCH", "gitstore_git_branch"); ok {
386+
gitStoreBranch = value
387+
}
384388
if value, ok := lookupEnv("OBJECTSTORE_ENDPOINT", "objectstore_endpoint"); ok {
385389
useObjectStore = true
386390
objectStoreEndpoint = value
@@ -515,7 +519,7 @@ func main() {
515519
}
516520
gitStoreRoot = filepath.Join(gitStoreLocalPath, "gitstore")
517521
authDir := filepath.Join(gitStoreRoot, "auths")
518-
gitStoreInst = store.NewGitTokenStore(gitStoreRemoteURL, gitStoreUser, gitStorePassword)
522+
gitStoreInst = store.NewGitTokenStore(gitStoreRemoteURL, gitStoreUser, gitStorePassword, gitStoreBranch)
519523
gitStoreInst.SetBaseDir(authDir)
520524
if errRepo := gitStoreInst.EnsureRepository(); errRepo != nil {
521525
log.Errorf("failed to prepare git token store: %v", errRepo)

config.example.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ max-retry-credentials: 0
8787
# Maximum wait time in seconds for a cooled-down credential before triggering a retry.
8888
max-retry-interval: 30
8989

90+
# When true, disable auth/model cooldown scheduling globally (prevents blackout windows after failure states).
91+
disable-cooling: false
92+
9093
# Quota exceeded behavior
9194
quota-exceeded:
9295
switch-project: true # Whether to automatically switch to another project when a quota is exceeded
@@ -106,12 +109,21 @@ enable-gemini-cli-endpoint: false
106109

107110
# When > 0, emit blank lines every N seconds for non-streaming responses to prevent idle timeouts.
108111
nonstream-keepalive-interval: 0
109-
110112
# Streaming behavior (SSE keep-alives + safe bootstrap retries).
111113
# streaming:
112114
# keepalive-seconds: 15 # Default: 0 (disabled). <= 0 disables keep-alives.
113115
# bootstrap-retries: 1 # Default: 0 (disabled). Retries before first byte is sent.
114116

117+
# Signature cache validation for thinking blocks (Antigravity/Claude).
118+
# When true (default), cached signatures are preferred and validated.
119+
# When false, client signatures are used directly after normalization (bypass mode for testing).
120+
# antigravity-signature-cache-enabled: true
121+
122+
# Bypass mode signature validation strictness (only applies when signature cache is disabled).
123+
# When true, validates full Claude protobuf tree (Field 2 -> Field 1 structure).
124+
# When false (default), only checks R/E prefix + base64 + first byte 0x12.
125+
# antigravity-signature-bypass-strict: false
126+
115127
# Gemini API keys
116128
# gemini-api-key:
117129
# - api-key: "AIzaSy...01"

docs/session-2026-04-11.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Session 2026-04-11
2+
3+
- Targeted upstream sync: `CLIProxyAPI v6.9.22`
4+
- Merge base from shipping line: `v0.3.0-dev-0.53` on `main`
5+
- Upstream merge branch: `sync-upstream-v6.9.18-to-v6.9.22`
6+
- Conflict resolution:
7+
- kept ProxyPilot-local `.gitignore` entries while accepting upstream code changes
8+
- updated upstream tracking markers and release metadata to `v6.9.22`
9+
- Planned release target after validation: `v0.3.0-dev-0.54`

0 commit comments

Comments
 (0)