Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2ca646a
docs(changelog): 修正 v0.2.3 发布链接与日期;
ThreeFish-AI Apr 16, 2026
1b2e2d6
style(dashboard): 缩小「今日费用估算」卡片费用数字字体使其单行显示;
ThreeFish-AI Apr 16, 2026
0027088
Merge pull request #181 from ThreeFish-AI/vk/90ce-41-9106-33-4842
ThreeFish-AI Apr 16, 2026
27d7cb0
refactor(thinking-strip): 条件化 thinking block 剥离,仅跨供应商场景触发;
ThreeFish-AI Apr 16, 2026
a674210
Merge pull request #182 from ThreeFish-AI/vk/84f5-debug-anthropic
ThreeFish-AI Apr 16, 2026
e3bc912
style(format): 拆分长行并移除未使用导入,提升代码可读性;
ThreeFish-AI Apr 16, 2026
9bee5b3
build(version): 版本号升级至 0.2.4a1 进入下一迭代周期;
ThreeFish-AI Apr 16, 2026
e7437e6
chore(config): 调整 token_budget 至 60000000;
ThreeFish-AI Apr 16, 2026
5c7fa01
chore(config): 默认关闭 quota_guard 与 antigravity 供应商;
ThreeFish-AI Apr 16, 2026
ca48eac
style(cost-format): 费用金额显示精度从 4 位缩减至 2 位小数;
ThreeFish-AI Apr 16, 2026
8ba7a58
Merge pull request #184 from ThreeFish-AI/vk/accc-2
ThreeFish-AI Apr 16, 2026
b5550a6
build(version): 版本号升级至 0.2.4a2 进入下一迭代周期;
ThreeFish-AI Apr 17, 2026
7cefa0d
ci(release): 移除发布流水线中的 Update Changelog 自动化阶段;
ThreeFish-AI Apr 17, 2026
97893bc
Merge pull request #185 from ThreeFish-AI/vk/0ea3-release-yaml-upd
ThreeFish-AI Apr 17, 2026
065af97
fix(dashboard-legend): 统一三个图表的 Legend 排序与供应商状态 Tiers 顺序一致;
ThreeFish-AI Apr 17, 2026
3a6b059
Merge pull request #186 from ThreeFish-AI/vk/8def-legend-vendors-a
ThreeFish-AI Apr 17, 2026
fc8826c
feat(pre-commit): 新增 pre-commit hooks 配置,在 commit 前自动执行 Ruff lint/for…
ThreeFish-AI Apr 17, 2026
c2ee552
style(whitespace): 修复行尾空白与文件末尾换行符缺失,由 pre-commit hooks 首次全量扫描自动修正;
ThreeFish-AI Apr 17, 2026
19e32d5
Merge pull request #187 from ThreeFish-AI/vk/8389-pre-commit-hooks
ThreeFish-AI Apr 17, 2026
b5a26bb
build(version): 版本升级至 0.2.4a3;
ThreeFish-AI Apr 17, 2026
a1ab8d9
chore(config): 上调 Claude 供应商 token_budget 至 65,000,000;
ThreeFish-AI Apr 17, 2026
3a06c09
fix(request-normalizer): 重设计 zhipu→anthropic 跨供应商 tool_use/tool_resul…
ThreeFish-AI Apr 17, 2026
9712ee1
Merge pull request #188 from ThreeFish-AI/vk/a921-fix-vendor-zhipu
ThreeFish-AI Apr 17, 2026
a4778f1
build(version): 版本升级至 0.2.4a4;
ThreeFish-AI Apr 17, 2026
62b4ad2
build(version): 同步更新 pyproject.toml 版本至 0.2.4a4;
ThreeFish-AI Apr 17, 2026
51e43fc
docs(framework): 正交分解架构文档为枢纽+专题子文档,同步代码库事实;
ThreeFish-AI Apr 17, 2026
461f8b6
docs(arch): 二轮校准修正事实性偏差 — NativeAnthropicVendor 去抽象化、FailoverConfig 补…
ThreeFish-AI Apr 17, 2026
23a2d13
Merge pull request #189 from ThreeFish-AI/vk/4d2a-preening-substra
ThreeFish-AI Apr 17, 2026
2c9319a
docs(user-guide): 正交分解用户指南为枢纽+专题子文档,校准全部语义偏差;
ThreeFish-AI Apr 17, 2026
2773c9e
docs(user-guide): 二轮校准修正全部事实性偏差 — 锚点断裂、CLI 参数、配置加载语义、迁移条件精确化;
ThreeFish-AI Apr 17, 2026
31ba715
Merge pull request #190 from ThreeFish-AI/vk/27b8-preening-substra
ThreeFish-AI Apr 17, 2026
a45650e
feat(vendor-channels): 新增 zhipu/copilot 供应商专属转换通道,修复跨供应商故障转移格式不兼容;
ThreeFish-AI Apr 17, 2026
3d4dc54
refactor(vendor-channels): 合并 anthropic 通道到 vendor_channels 注册表,统一所有供…
ThreeFish-AI Apr 18, 2026
4daeba9
fix(vendor-channels): 区分 anthropic 宽松触发与 zhipu/copilot 严格触发,防止纯会话误激活通道
ThreeFish-AI Apr 18, 2026
b82521c
style(arch): 统一 Markdown 表格列对齐格式;
ThreeFish-AI Apr 18, 2026
84d5563
style(docs): 统一指南与运维文档 Markdown 表格列对齐格式;
ThreeFish-AI Apr 18, 2026
592945c
refactor(vendor-channels): 将供应商转换通道从目标专属重构为源→目标绑定模型;
ThreeFish-AI Apr 18, 2026
fbc6aa4
docs(readme): 校准架构图 Tier 排序、补全 CLI auth 子命令与格式转换描述;
ThreeFish-AI Apr 18, 2026
8e3d639
Merge pull request #191 from ThreeFish-AI/vk/c1e8-readme-readme-re
ThreeFish-AI Apr 18, 2026
b11dede
Merge pull request #192 from ThreeFish-AI/vk/a921-fix-vendor-zhipu
ThreeFish-AI Apr 18, 2026
14ce901
refactor(vendor-channels): 将 vendor 转换专属函数从 request_normalizer 迁入 ven…
ThreeFish-AI Apr 18, 2026
0774766
Merge pull request #193 from ThreeFish-AI/vk/a921-fix-vendor-zhipu
ThreeFish-AI Apr 18, 2026
9343da4
build(version): 升级版本号至 0.2.4a5;
ThreeFish-AI Apr 18, 2026
6348147
chore(assets): 更新 dashboard v0.2.3 截图;
ThreeFish-AI Apr 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 2 additions & 133 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# =============================================================================
# coding-proxy: PyPI Publishing Pipeline (4-Stage Unified Pipeline)
# coding-proxy: PyPI Publishing Pipeline (3-Stage Unified Pipeline)
# =============================================================================
# Trigger: GitHub Release publication event (release.types: [published])
#
# Architecture: 4-Stage Serial Pipeline (prerelease only — 所有生产发布均走预发布)
# Architecture: 3-Stage Serial Pipeline (prerelease only — 所有生产发布均走预发布)
#
# Stage 1 (build): 矩阵构建 3.12/3.13/3.14,上传 artifacts
# Stage 2 (publish-testpypi): 发布到 TestPyPI 供验证
# Stage 3 (publish-to-pypi): ⏸ Production Approval Gate (environment: pypi)
# 审批通过后自动:Promote Release + Publish to PyPI
# Stage 4 (update-changelog): 从 Release notes 生成 Changelog PR → master
#
# 设计决策 — Stage 3 合并审批与发布的理由:
# pypa/gh-action-pypi-publish@release/v1 始终优先尝试 OIDC Trusted Publishing。
Expand All @@ -21,9 +20,6 @@
# Pre-requisites — 需要在 GitHub Settings 一次性手动配置:
# 1. repo → Settings → Environments → "pypi"
# → Required reviewers: 添加审批人员(Production Approval Gate 所需)
# 2. repo → Settings → Actions → General → Workflow permissions
# → "Read and write permissions"(Stage 4 推分支所需)
# → 勾选 "Allow GitHub Actions to create and approve pull requests"
#
# Authentication:
# - TEST_PYPI_API_TOKEN: TestPyPI API Token(repository secret)
Expand Down Expand Up @@ -197,130 +193,3 @@ jobs:
with:
skip-existing: true
verbose: true

# ===========================================================================
# Stage 5: UPDATE CHANGELOG -- 自动生成 Changelog PR → master
# ===========================================================================
update-changelog:
name: Update Changelog
runs-on: ubuntu-latest
needs: publish-to-pypi
if: github.event.release.prerelease == true
timeout-minutes: 10
permissions:
contents: write # git push 新分支
pull-requests: write # 创建 PR

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: true

- name: Extract stable version from prerelease tag
id: version
run: |
PRERELEASE_TAG="${{ github.ref_name }}"
# v0.2.0a1 → v0.2.0(移除预发布后缀 a*/b*/rc*)
STABLE_VERSION=$(echo "$PRERELEASE_TAG" | sed 's/\(v[0-9]*\.[0-9]*\.[0-9]*\).*/\1/')
echo "prerelease_tag=$PRERELEASE_TAG" >> "$GITHUB_OUTPUT"
echo "stable_version=$STABLE_VERSION" >> "$GITHUB_OUTPUT"
echo "branch_name=chore/changelog-$STABLE_VERSION" >> "$GITHUB_OUTPUT"
echo "Extracted: $PRERELEASE_TAG → $STABLE_VERSION"

- name: Check if Changelog entry already exists
id: check
run: |
STABLE="${{ steps.version.outputs.stable_version }}"
if grep -qF "[$STABLE]" CHANGELOG.md; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "ℹ️ Changelog entry for $STABLE already exists, skipping PR creation"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "✅ No existing entry for $STABLE, will create PR"
fi

- name: Fetch release body and update CHANGELOG.md
if: steps.check.outputs.exists == 'false'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const { owner, repo } = context.repo;

// 通过 API 获取 Release body,避免 shell 特殊字符注入问题
const release = await github.rest.repos.getReleaseByTag({
owner,
repo,
tag: '${{ steps.version.outputs.prerelease_tag }}',
});

const stable = '${{ steps.version.outputs.stable_version }}';
const date = new Date().toISOString().slice(0, 10);
const releaseUrl = `https://github.com/${owner}/${repo}/releases/tag/${{ steps.version.outputs.prerelease_tag }}`;
const body = release.data.body || '';

// 构建新条目
const newEntry = `\n## [${stable}](${releaseUrl}) — ${date}\n\n${body}\n`;

// 读取 CHANGELOG.md,在 ## [Unreleased] 行后插入新条目
let content = fs.readFileSync('CHANGELOG.md', 'utf8');
const marker = '## [Unreleased]';
const idx = content.indexOf(marker);
if (idx === -1) {
core.setFailed('CHANGELOG.md 中未找到 ## [Unreleased] 标记,无法插入条目');
return;
}
const insertPos = idx + marker.length;
content = content.slice(0, insertPos) + newEntry + content.slice(insertPos);
fs.writeFileSync('CHANGELOG.md', content, 'utf8');
core.info(`✅ CHANGELOG.md updated with entry for ${stable}`);

- name: Create branch and commit
if: steps.check.outputs.exists == 'false'
run: |
BRANCH="${{ steps.version.outputs.branch_name }}"
STABLE="${{ steps.version.outputs.stable_version }}"

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git checkout -b "$BRANCH"
git add CHANGELOG.md
git commit -m "docs(changelog): add entry for $STABLE"
git push origin "$BRANCH"

- name: Create Pull Request
if: steps.check.outputs.exists == 'false'
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo;
const stable = '${{ steps.version.outputs.stable_version }}';
const branch = '${{ steps.version.outputs.branch_name }}';
const prereleaseTag = '${{ steps.version.outputs.prerelease_tag }}';
const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${{ github.run_id }}`;

const pr = await github.rest.pulls.create({
owner,
repo,
title: `docs(changelog): 补充 ${stable} 发版说明`,
body: [
`## 摘要`,
``,
`自动生成的 PR,为 **${stable}** 正式版补充 CHANGELOG 条目。`,
``,
`- 来源:[\`${prereleaseTag}\`](https://github.com/${owner}/${repo}/releases/tag/${prereleaseTag}) Release notes`,
`- 目标分支:\`master\``,
``,
`请审阅 CHANGELOG 条目后合并。`,
``,
`> 🤖 由 [发布流水线](${runUrl}) 自动生成`,
].join('\n'),
head: branch,
base: 'master',
});

core.notice(`✅ PR created: ${pr.data.html_url}`);

57 changes: 57 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# =============================================================================
# coding-proxy: Pre-commit Hooks Configuration
# =============================================================================
# 目的: 在代码提交前自动执行 Ruff lint/format 及通用卫生检查,作为 CI 的前置守护
#
# 设计决策:使用 local hook(language: system + uv run)而非 astral-sh/ruff-pre-commit
# - 遵循 Single Source of Truth 原则:Ruff 版本由 uv.lock 唯一管控,消除版本漂移
# - 与 CI 命令形态完全镜像(uv run ruff check/format)
# - 符合 AGENTS.md 包管理规范(统一使用 uv)
#
# 安装:uv run pre-commit install
# 手动全量检查:uv run pre-commit run --all-files
# =============================================================================

minimum_pre_commit_version: "4.0.0"

repos:
# ---------------------------------------------------------------------------
# 通用代码卫生检查(pre-commit-hooks 官方钩子集)
# 轻量级、无额外依赖、执行极快
# ---------------------------------------------------------------------------
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace # 去除行尾空白
- id: end-of-file-fixer # 确保文件以换行符结尾
- id: check-yaml
args: ["--unsafe"] # 兼容 GitHub Actions ${{ }} 表达式语法
- id: check-toml # 校验 TOML 语法(pyproject.toml)
- id: check-merge-conflict # 阻止提交含未解决 merge conflict 标记的文件
- id: check-added-large-files
args: ["--maxkb=1024"] # 阈值 1MB(assets/dashboard-v0.2.3.png 为 944KB)

# ---------------------------------------------------------------------------
# Ruff: local hook,直接调用 uv 安装的 Ruff(与 CI 版本完全一致)
# 前置条件:uv sync --dev 已执行
# ---------------------------------------------------------------------------
- repo: local
hooks:
# 对应 CI: uv run ruff check .
# --fix: 自动修复安全可修复问题(isort、UP 现代化等),降低开发摩擦
# --exit-non-zero-on-fix: 修复后返回非零码,触发 git 重新暂存已修复文件
- id: ruff-lint
name: Ruff (lint + auto-fix)
language: system
entry: uv run ruff check --fix --exit-non-zero-on-fix
types_or: [python, pyi]
require_serial: false

# 对应 CI: uv run ruff format --check .
# 本地直接 format(自动修复格式),CI 保留 --check 模式作为最终防线
- id: ruff-format
name: Ruff (format)
language: system
entry: uv run ruff format
types_or: [python, pyi]
require_serial: false
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
2. **Temp Management**: 临时产物(执行计划等)一律收敛至 `.temp/` 并及时清理;
3. **Link Validity**: 确保所有引用的 URL 可访问且具备明确的上下文价值;
4. **Git Commit**: 在需要提交变更到 Git 时,一律使用 Shell 调用 Claude Code 的自定义 Slash Command: `/commit` 进行 git commit 操作(若环境中未安装 Claude Code,则直接读取 `~/.claude/commands/commit.md`,按照其中的规则进行 git commit 操作)。不要执行 Rebase。
5. **Pre-commit Hooks**: 克隆仓库后执行 `uv run pre-commit install` 激活本地 Git hooks,使 Ruff lint(含 auto-fix)、Ruff format 及通用代码卫生检查在每次 commit 前自动运行。若 hooks 自动修复了问题,提交会被中断,执行 `git add -p` 审阅修复内容后重新提交即可。
- **Package Management Standardization (包管理规范)**:
1. **Python**: 严禁使用 pip/poetry,**必须**统一使用 `uv` 进行包管理与脚本执行(如 `uv run`);
2. **JavaScript/TypeScript**: 严禁使用 npm/yarn,**必须**统一使用 `pnpm` 进行包管理与脚本执行。
Expand Down
12 changes: 8 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

## [Unreleased]

## [v0.2.3](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.2.3a1) — 2026-04-15
- fix(request-normalizer): 重设计 zhipu→anthropic 跨供应商 tool_use/tool_result 配对修复——以单遍自包含 `enforce_anthropic_tool_pairing` 替代原有多步串联管线(剥离→重定位→孤儿修复),消除步骤间隐式依赖导致的孤儿 tool_use 漏修问题,彻底根治 `tool_use ids were found without tool_result blocks` 400 异常;
- refactor(vendor-channels): 将供应商转换通道从「目标 vendor 专属」重构为「源→目标绑定」模型——注册表键从 `target_vendor` 改为 `(source, target)` 二元组,通道函数从 `prepare_for_X` 重命名为 `prepare_X_to_Y`,触发逻辑从 `_needs_vendor_channel` 替换为 `_determine_source_vendor`(基于请求内 `failed_tier_name` 和会话历史推断源 vendor),未注册的转换对(如 anthropic→zhipu)不触发任何通道;
- feat(vendor-channels): 新增 zhipu→anthropic、zhipu→copilot、copilot→zhipu 三条源→目标绑定转换通道,在跨供应商故障转移时自动清理源 vendor 产物(thinking 块、cache_control 字段、thinking 参数、tool_use/tool_result 配对),消除 `likely format incompatibility (400 + tool_results)` 错误;

## [v0.2.3](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.2.3) — 2026-04-16

- feat(dashboard): 新增实时 Web Dashboard 页面,聚合展示流量与用量统计;
- docs(user-guide): 补充 POST /v1/messages 完整 API 参考文档;
Expand Down Expand Up @@ -71,9 +75,9 @@
## [v0.1.1](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.1.1) — 2026-04-05

> [!IMPORTANT]
>
> **🎉 coding-proxy MVP 惊艳登场!**
>
>
> **🎉 coding-proxy MVP 惊艳登场!**
>
> 仅需配置一行环境变量,立刻为你的 Claude Code 接入“永不宕机”的多源智能引擎。主供应商打盹?毫秒级自动无缝切换备用通道,全天候护航你的编码心流,向打断大声说不!

### ✨ 核心亮点
Expand Down
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ When you're deeply immersed in your coding "zone" with **Claude Code** (or any A
<img src="assets/dashboard-v0.2.3.png">
</div>

- **⛓️ N-tier Chained Failover**: Autonomous descending sequence, supporting Claude's official plans, as well as Coding Plans from GitHub Copilot, Z AI, MiniMax, Alibaba Qwen, Xiaomi, Kimi, Doubao, etc.
- **⛓️ N-tier Chained Failover**: Autonomous descending sequence, supporting Claude's official plans, as well as Coding Plans from GitHub Copilot, Google Antigravity, Z AI, MiniMax, Alibaba Qwen, Xiaomi, Kimi, Doubao, etc.
- **🛡️ Smart Resilience & Quota Guardians**: Every single vendor node comes fully armed with an independent **Circuit Breaker** and **Quota Guard** to proactively dodge avalanches without breaking a sweat.
- **👻 Phantom-like Transparency**: **100% transparent** to the client! No code tweaks required. Overwrite `ANTHROPIC_BASE_URL` with a single line, and you're good to go.
- **🔄 Universal Alchemy (Formats & Models)**: Native support for two-way request/streaming (SSE) translations between Anthropic ←→ Gemini. Plus, auto/DIY model name mapping (e.g., effortlessly morphing `claude-*` into `glm-*`).
- **🔄 Universal Alchemy (Formats & Models)**: Native support for two-way request/streaming (SSE) translations between Anthropic ←→ Gemini and Anthropic ←→ OpenAI. Plus, auto/DIY model name mapping (e.g., effortlessly morphing `claude-*` into `glm-*`).
- **📊 Extreme Observability**: Built-in, zero-BS local monitoring powered by a `SQLite WAL`. The CLI provides a one-click detailed Token usage dashboard (`coding-proxy usage`).
- **⚡ Featherweight Standalone Deployment**: A fully asynchronous architecture (`FastAPI` + `httpx`). Zero dependency on Redis, message queues, or other heavy machinery—absolutely no extra baggage for your dev rig.

Expand Down Expand Up @@ -95,6 +95,7 @@ claude
| Command | Description | Example Usage |
| :------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- |
| `start` | **Fire up the proxy server.** Supports custom ports and configuration paths. | `coding-proxy start -p 8080 -c ~/config.yaml` |
| `auth` | **Manage OAuth credentials.** Sub-commands: `login` (browser OAuth), `status` (token validity), `reauth` (re-authenticate), `logout` (clear tokens). | `coding-proxy auth login -p github` |
| `status` | **Check proxy health.** Shows circuit breaker states (OPEN/CLOSED) and quota status across all tiers. | `coding-proxy status` |
| `usage` | **Token Stats Dashboard.** Stalks every single token consumed, failovers triggered, and latency across day/vendor/model dimensions. | `coding-proxy usage -d 7 -v anthropic` |
| `reset` | **The emergency flush button.** Force-reset all circuit breakers and quotas instantly when you've confirmed the main vendor is back from the dead. | `coding-proxy reset` |
Expand All @@ -118,40 +119,40 @@ graph RL

subgraph CodingProxy["⚡ coding-proxy"]
direction RL

Router["RequestRouter<br/><code>routing/router.py</code>"]:::router

Router -->NTier

subgraph NTier["N-tier"]
direction TB

subgraph Tier0 ["Tier 0: Anthropic"]
subgraph Tier0 ["Tier 0: Zhipu"]
direction RL
G0{"CB / Quota"}:::gateway -- "✅ Pass" --> API0(("Anthropic API")):::api
G0{"CB / Quota"}:::gateway -- "✅ Pass" --> API0(("GLM API")):::api
end

subgraph Tier1 ["Tier 1: GitHub Copilot"]
subgraph Tier1 ["Tier 1: Anthropic"]
direction RL
G1{"CB / Quota"}:::gateway -- "✅ Pass" --> API1(("Copilot API")):::api
G1{"CB / Quota"}:::gateway -- "✅ Pass" --> API1(("Anthropic API")):::api
end

subgraph Tier2 ["Tier 2: Google Antigravity"]
subgraph Tier2 ["Tier 2: GitHub Copilot"]
direction RL
G2{"CB / Quota"}:::gateway -- "✅ Pass" --> API2(("Gemini API")):::api
G2{"CB / Quota"}:::gateway -- "✅ Pass" --> API2(("Copilot API")):::api
end

subgraph TierN ["Tier N: Zhipu"]
subgraph Tier3 ["Tier 3: Google Antigravity"]
direction RL
APIN(("GLM API")):::fallback
API3(("Gemini API")):::fallback
end

Tier0 -. "❌ Blocked / API Error" .-> Tier1
Tier1 -. "❌ Blocked / API Error" .-> Tier2
Tier2 -. "🆘 Safety Net Downgrade" .-> TierN
Tier2 -. "🆘 Safety Net Downgrade" .-> Tier3
end

end
end

Client -->|"POST /v1/messages"| CodingProxy
```
Expand Down
Binary file modified assets/dashboard-v0.2.3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading