fix(streaming): add heartbeat keepalive + connection pooling#27
Open
garywhat wants to merge 16 commits into
Open
fix(streaming): add heartbeat keepalive + connection pooling#27garywhat wants to merge 16 commits into
garywhat wants to merge 16 commits into
Conversation
reset-password only sets auth_password_hash but does not ensure auth_jwt_secret exists. When the database is wiped and password is reset via CLI, the user cannot log in because JWT token generation fails with 'JWT secret not configured'. Check for missing auth_jwt_secret during reset-password and generate one if needed, matching the behavior of the /api/auth/setup flow. Closes vibe-coding-labs#14
…word-jwt-secret fix(reset-password): generate JWT secret if missing
…-labs#21) 扫码登录的 fetchUserInfoWithPtKey 此前裸调 v1 userInfo + 写死 clientVersion 2.4.5,与 7fcf9df 适配 JoyCode 2.7 时引入的 color gateway 鉴权(HMAC 签名 + v2 端点 + 2.7.5)脱节。二维码生成与扫码 轮询(qr.m.jd.com)均正常,但确认后用 pt_key 换用户信息这步走的 是 2.7 已弃用的旧路径,导致即使拿到有效 pt_key 也换不出用户信息。 改为复用 joycode.Client.UserInfo(),与 OAuth 登录走同一套鉴权, 消除两条登录链路的分叉。 Closes vibe-coding-labs#21 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ogin-color-gateway fix(auth): 扫码登录走 color gateway 鉴权,修复 vibe-coding-labs#21 京东登录失败
仓库已从 vibe-coding-labs/JoyCodeProxy 改名为 JoyCode2Api,本次把代码侧 全面对齐到新名: - go module: github.com/vibe-coding-labs/JoyCodeProxy → JoyCode2Api - 23 个 .go 文件的 import 路径同步更新 - cmd/JoyCodeProxy/ 目录改名 cmd/JoyCode2Api/(git mv 保留历史) - 构建配置跟随: Dockerfile / scripts/release.sh / web/vite.config.ts - 二进制名与发布产物名 JoyCodeProxy → JoyCode2Api - 前端 GitHub 链接、README、dashboard ghRepo 常量对齐新仓库 - 重新构建前端 embed 资源 不改: docs/superpowers/plans/ 历史规划文档(保持历史原貌); JWT issuer "joycode-proxy"(改会使现有 dashboard 会话全部失效,不在范围); .gitignore 中 snake_case/kebab 产物防御规则(保留以防本地旧二进制误提交)。 验证: go build/vet/test 全过;前端构建产物无旧链接残留; 启动重构后二进制 /health、/api/qr-login/init、/v1/models 路由均正常。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…/module-path-joycode2api refactor: module 路径与二进制名对齐 JoyCode2Api
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Switch sqlite driver from mattn/go-sqlite3 (CGO) to modernc.org/sqlite (pure Go). With CGO disabled the binary cross-compiles to darwin without a macOS SDK, restoring the darwin-arm64 release artifact that v0.6.0 had to ship without. Driver name sqlite3 -> sqlite; DSNs adapted (proxy.db WAL via _pragma, read-only JoyCode IDE db via file: URI mode=ro). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
新增「从源码构建」章节:git clone + CGO_ENABLED=0 编译当前平台的说明, 以及一段可原样复制粘贴给 AI Agent(Claude Code / Cursor 等)的一键指令, 由 Agent 自动完成 clone / build / 后台启动 / 默认浏览器打开 Dashboard。 顺带把构建章节的 Go 版本要求从 1.22+ 修正为 1.25+(与 go.mod 一致)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refactor base URLs to be configurable via environment variables.
Make BaseURL and SaasBaseURL configurable
跟进 PR vibe-coding-labs#24 的格式规范化:var 块与 envOr 改用 tab 缩进、const 块等号重新对齐。功能改动由 @WslzGmzs 贡献,本提交仅做 gofmt,无逻辑变更。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upstream JoyCode API buffers the entire response before sending anything
(TTFB 10-30s for reasoning models). Without keepalive, downstream clients
(Claude Code, OpenAI clients) time out or show "no response" during this
gap.
- Add SSE heartbeat goroutines for OpenAI and Anthropic streaming paths
that send comment lines (": ...") every 15s while waiting for upstream
- Parse usage from SSE data lines in OpenAI streaming for token logging
- Add shared http.Transport with connection pooling in joycode client
- Add graceful shutdown via stopCh for background goroutines in serve
- Add pkg/common.IsTimeoutError helper for timeout detection
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Resolve conflict in pkg/joycode/client.go: keep both defaultTransport (connection pooling from this PR) and envOr (configurable BaseURL from upstream vibe-coding-labs#24). Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
CherryStudio and other OpenAI-compatible clients hang in "generating" state after the upstream finishes because: 1. The OpenAI streaming path only forwards upstream lines — if the upstream omits `data: [DONE]` (premature close, certain error paths), the client never receives the stream terminator. Now we track `sawDone` and always send a final `data: [DONE]\n\n` if it wasn't seen. 2. The heartbeat goroutine can race with the main goroutine writing to the same http.ResponseWriter. `close(stopHeartbeat)` signals exit but doesn't wait for the goroutine to actually stop — if it's mid-write when the main goroutine starts forwarding upstream data, the writes interleave and corrupt the SSE stream. Now we use a `heartbeatDone` channel and `<-heartbeatDone` to ensure the heartbeat goroutine has fully exited before any downstream writes begin. Applied to all three streaming paths: OpenAI, Anthropic (translated), and native Anthropic. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Upstream JoyCode API buffers the entire response before sending anything (TTFB 10-30s for reasoning models). Without keepalive, downstream clients (Claude Code, OpenAI clients) time out or show "no response" during this gap.
pkg/openai/chat.go) and Anthropic (pkg/anthropic/handler.go) streaming paths that send comment lines (": ...") every 15s while waiting for upstreamusagefrom SSE data lines in OpenAI streaming so token consumption is logged correctly (previously missing for streaming requests)http.Transportwith connection pooling inpkg/joycode/client.goso clients reuse TCP connections instead of dialing anew for every requeststopChfor background goroutines incmd/JoyCode2Api/serve.gopkg/common.IsTimeoutErrorhelper for timeout detection across packagesBackground
This addresses the streaming stability issues reported in #2 and #12 (the "stream failed / read first line: EOF" symptom that occurs when the upstream TTFB exceeds client timeouts).
Test plan
pingevents during upstream waitGenerated with Devin